2017-08-16 30 views
9

Tôi có một bảng và một trong các trường là trường ngày.chọn ngày từ bảng thành hai cột

Tôi đã được yêu cầu viết một truy vấn trả về danh sách các ngày riêng biệt (được đặt hàng) trong cột A và sau đó có cột khác, nói B của các ngày trong đó ngày trong cột B là ngày lớn nhất nhỏ hơn cột A.

MyDateField 

    2017-01-01 
    2017-01-01 
    2017-01-01 
    2017-01-02 
    2017-01-02 
    2017-01-03 
    2017-01-04 
    2017-01-05 
    2017-01-05 
    2017-01-05 

trả lời cần

2017-01-05  2017-01-04 
    2017-01-04  2017-01-03 
    2017-01-03  2017-01-02 
    2017-01-02  2017-01-01 
    2017-01-01  
+0

Liệu cột này B cũng đến từ ông cùng một bảng, hoặc chỉ là một 'date_column - '1 ngày'' sẽ làm điều đó? –

+0

nó đến từ cùng một bảng – mHelpMe

Trả lời

7

Nếu bạn đang sử dụng SQL-server 2012+, sau đó bạn có thể sử dụng LAG() để lấy ngày lớn nhất cuối cùng ra khỏi bảng:

SELECT t.date, 
     LAG(t.date,1) OVER(ORDER BY t.date) as last_biggest_date 
FROM (SELECT DISTINCT s.dateField FROM YourTable s) t 
+1

Chỉ cần lưu ý rằng đây là SQL Server 2012+, mặc dù ông đã không đăng DBMS của mình. – justiceorjustus

+0

@justiceorjustus Bạn chính xác, đã chỉnh sửa. – sagi

+1

đó là rực rỡ! – mHelpMe

1

Bạn có thể sử dụng áp dụng subquery để trở lại ngày nhỏ hơn trong cột thứ hai:

select distinct t1.MyDateField, x.MyDateField 
from MyTable t1 
outer apply (select max(MyDateField) MyDateField 
      from MyTable t2 
      where t1.MyDateField> t2.MyDateField) x 
+0

Chỉ cần một đầu lên ... 'TOP 1' bên ngoài áp dụng không được đảm bảo là một trong những bạn muốn (hoặc thậm chí giống nhau mỗi lần), mà không chỉ định một 'ORDER BY' trong cùng một truy vấn phụ. – scsimon

+0

Bạn nói đúng, tôi chuyển 'TOP 1' bằng' MAX() 'để nó luôn trả về ngày chính xác – Mat

2

Bạn có thể làm điều này với một CTE trong số những thứ khác. Điều này sẽ có danh sách các ngày riêng biệt và sau đó sử dụng tự tham gia.

with cte as(
    select distinct 
     MyDateField 
    from 
     YourTable) 

select 
    c.MyDateField 
    ,max(c2.MyDateField) as MaxDate 
from 
    cte c 
left join cte c2 on c2.MyDateField < c.MyDateField 
group by 
    c.MyDateField 
order by 
    c.MyDateField 

Hoặc đơn giản tự tham gia mà không có một CTE

--in this case DISTINCT isn't really needed, but left in case there are other columns 
select distinct 
    c.MyDateField 
    ,max(c2.MyDateField) as MaxDate 
from 
    myTable c 
left join myTable c2 on c2.MyDateField < c.MyDateField 
group by 
    c.MyDateField 
order by 
    c.MyDateField 
+0

Tôi không biết cú pháp CT $ MSQL, nhưng điều này sẽ hoạt động, ngay cả khi không có CTE ... –

+0

Bạn là đúng @UsagiMiyamoto, tôi chỉ thấy dễ đọc hơn cho rất nhiều người. – scsimon

0
SELECT d, LAG(d) OVER (ORDER BY d) AS d2 
    FROM (
      SELECT DISTINCT d 
       FROM (VALUES ('2017-01-01'), 
          ('2017-01-01'), 
          ('2017-01-01'), 
          ('2017-01-02'), 
          ('2017-01-02'), 
          ('2017-01-03'), 
          ('2017-01-04'), 
          ('2017-01-05'), 
          ('2017-01-05'), 
          ('2017-01-05')) AS dates(d) 
     ) AS d(d) 
ORDER BY d DESC; 

Output:

d   d2 
---------- ---------- 
2017-01-05 2017-01-04 
2017-01-04 2017-01-03 
2017-01-03 2017-01-02 
2017-01-02 2017-01-01 
2017-01-01 NULL 
0
with CTE as(
select 
ROW_NUMBER() over (order by MyDateField) 'RN', 
MyDateField from TempTable 
group by MyDateField) 
select t2.MyDateField,t1.MyDateField from CTE t1 
right join CTE t2 
on t1.RN=t2.RN-1 
order by t2.MyDateField desc 
Các vấn đề liên quan