用户正在输入数据到我的" track ";表从.aspx页。他们为不同的活动输入一系列日期,如果他们想要提醒他们那个日期,就勾选一个复选框。我目前遇到的具体问题是限制in语句中的列:
SELECT [id], [name], MIN([DATE]) AS [MinDate]
FROM track UNPIVOT ([DATE] FOR d IN ([date1],[date2],[date2])) unpvt
GROUP BY [id], [name]
如果列date1chk
的值为1
,我只想包含date1
。同理,对于date2
,如果date2chk
为"1",等等。否则,date#
列不包含在in中。
在此之后,我的挑战是能够更新表,例如,如果date2
是最小值,那么date2chk
将从1
设置为0
。
非常感谢您的意见——这是我处理过的比较困难的问题之一。
编辑(感谢您的反馈):
数据ID Date1 Date1Chk Date2 Date2Chk Date3 Date3Chk
0 2013-01-15 0 2013-02-01 1 2013-02-10 1
1 2013-02-05 1 2013-02-05 1 2013-02-10 0
预期的结果
ID MinDate
0 2013-02-01
1 2013-02-05
假设我可以得到这个结果,我不确定我将如何更新表。例如,在"期望结果"中ID 1返回[Date1]和[Date2]都存在的最小值;我希望用户在第一个实例上停止提醒,所以[Date1Chk]将被设置为0(而不是[Date2Chk])。
您可以使用CROSS APPLY.. VALUES
而不是UNPIVOT
函数来解除数据透视,这允许您解除多个列的透视:
SELECT ID, MinDate = MIN(Date)
FROM track
CROSS APPLY
( VALUES
(Date1, date1chk),
(Date2, date2chk),
(Date3, date3chk)
) t (Date, datechk)
WHERE Datechk = 1
GROUP BY ID;
为了获得包含最小日期的列的名称,您可以稍微更改交叉应用以选择TOP 1
而不是使用MIN
:
SELECT ID, Name, MinDate = Date
FROM track
CROSS APPLY
( SELECT TOP 1 Date, datechk, Name
FROM (VALUES
(Date1, date1chk, 'Date1'),
(Date2, date2chk, 'Date2'),
(Date3, date3chk, 'Date3')
) t (Date, datechk, Name)
WHERE Datechk = 1
ORDER BY Date
) t;
SQL Fiddle示例
将unpivot
移动到子查询中,这样您就可以获取列的名称。然后where
条款解决你的问题:
select id, name, min([date]) as mindate
from (SELECT [id], [name], d, [DATE]
FROM track
UNPIVOT ([DATE] FOR d IN ([date1], [date2], [date2])) unpvt
) t
where (d = 'date1' and datecheck1 = 1) or
(d = 'date2' and datecheck2 = 1) or
(d = 'date3' and datecheck3 = 1)
GROUP BY [id], [name]
要获得具体的日期,使用row_number()
代替group by
:
select id, name, [date] as mindate
from (select id, name, [date],
row_number() over (partition by id, name order by [date]) as seqnum
from (SELECT [id], [name], d, [DATE]
FROM track
UNPIVOT ([DATE] FOR d IN ([date1], [date2], [date2])) unpvt
) t
where (d = 'date1' and datecheck1 = 1) or
(d = 'date2' and datecheck2 = 1) or
(d = 'date3' and datecheck3 = 1)
) t
where seqnum = 1