我有一张行动表。
该表在同一天同时有几个插槽。同一行动不能同时预订两次。我试图找出列出动作'A'的所有ID的方法,例如每个可用时间只列出一次,即使有两个可用的插槽,但如果'A'是预订了一段时间已经和这个时间的另一个插槽是空的,该插槽不会显示。 在我看来,我不知道T-SQL那么好。 我通过选择预订“A”的所有行来克服这个问题,选择未预订的所有不同(日期,时间开始和时间结束)并检查此时是否已经预订了“A”。但所有这些检查都是在软件级别完成的,那些对服务器的多次请求以及在程序中循环以执行与一个LIKELY SIMPLE sql请求相同的工作对我来说效率不高。 如果有办法做这样的事情:
SELECT ID FROM mytable
WHERE Action IS NULL AND (date, time_start, time_end **'ALL TOGETHER IN ONE ROW'**)
NOT IN (SELECT date, time_start, time_end FROM mytable
WHERE Action = 'A')
HAVING 'THOSE THREE BEING DISTINCT'
换句话说,我可以选择与其他行部分匹配的行吗?如果我只有一列可以比较,那将很简单,但有三列。
答案 0 :(得分:1)
在SQL Server中,我们通常使用WHILE而不是FOR。如果你想循环遍历表格,我相信你想要做的事情可以完成如下(理想情况下你的ID字段也是PRIMARY KEY)。现在只是将它插入到临时表中,但它可能会给你想要的结果:
-- DECLARE and set counters
DECLARE @curr INT, @prev INT, @max INT
SELECT @curr = 0, @prev = 0, @max = MAX(ID) FROM myTable
-- Make a simple temp table
CREATE TABLE #temp (ID INT)
-- Start looping
WHILE (@curr < @max)
BEGIN
-- Set our counter for the next row
SELECT @curr = MIN(ID) FROM myTable WHERE ID > @prev
-- Populate temp table with a self-join to compare slots
-- Slot must match on date + time but NOT have equal SLOT value
-- Will only INSERT if we meet our criteria i.e. neither slot booked
INSERT INTO #temp
SELECT DISTINCT A.ID
FROM myTable A
JOIN myTable B ON B.[Date] = A.[date] AND B.time_start = A.time_start AND B.time_end = A.time_end
WHERE A.[Action] IS NULL -- Indicates NO booking
AND B.[Action] IS NULL -- Indicates NO booking
AND A.SLOT <> B.SLOT
AND A.ID = @curr
-- Update our counter
SET @prev = @curr
END
-- Get all our records
SELECT * FROM #temp
-- Remove the sleeping dog ;)
DROP TABLE #temp
这里有一点冗余,因为它会检查所有行,即使在该时隙的第一行中找到了条件,但如果需要,可以从这里调整它。
你应该真的避免使用像“Date”和“Action”这样的字段名,因为这些是SQL中的保留字。
答案 1 :(得分:0)
你的问题有点不清楚,但我认为这会使你指向一个富有成效的方向。 SQL旨在对行集执行操作,而不是循环处理一行一行。以下代码会在每个日期/时间为每对插槽将您的数据关联到一行。您可以使用CASE
表达式(如图所示)添加指示行状态的列,然后可以添加WHERE
子句(未显示)以执行任何其他过滤。
-- Sample data.
declare @Samples as Table ( SampleId Int, Slot Int, EventDate Date, StartTime Time(0), EndTime Time(0), Action VarChar(10) );
insert into @Samples ( SampleId, Slot, EventDate, StartTime, EndTime, Action ) values
( 200, 1, '20150501', '00:00:00', '00:30:00', NULL ),
( 201, 2, '20150501', '00:00:00', '00:30:00', NULL ),
( 202, 1, '20150501', '00:30:00', '01:00:00', 'A' ),
( 203, 2, '20150501', '00:30:00', '01:00:00', NULL ),
( 204, 1, '20150501', '01:00:00', '01:30:00', NULL ),
( 205, 2, '20150501', '01:00:00', '01:30:00', 'A' ),
( 206, 1, '20150501', '01:30:00', '02:00:00', 'B' ),
( 207, 2, '20150501', '01:30:00', '02:00:00', 'B' );
select * from @Samples;
-- Data correleated for each date/time.
select Slot1.EventDate, Slot1.StartTime, Slot1.EndTime,
Slot1.Action as Action1, Slot2.Action as Action2,
Coalesce( Slot1.Action, Slot2.Action ) as SummaryAction,
case when Slot1.Action = Slot2.Action then 'ERROR!' else 'Okay.' end as Status
from @Samples as Slot1 inner join
@Samples as Slot2 on Slot2.EventDate = Slot1.EventDate and Slot2.StartTime = Slot1.StartTime and
Slot1.Slot = 1 and Slot2.Slot = 2;