2015-05-24 82 views
0

我有一個操作表。 Table選擇與另一個表中的行部分匹配的行

該表在同一天有幾個插槽。同樣的行動不能在同一時間預訂兩次。我試圖想出列出所有行爲'A'的ID的方式,例如,即使有兩個插槽可用,每個可用時間也只列出一次,但如果'A'是書籍一段時間已經和此時的另一個插槽是空的,該插槽不會顯示。 在我看來,我並不瞭解T-SQL。 我通過選擇預訂'A'的所有行,選擇未預訂的所有不同的(日期,時間開始和時間結束)並檢查'A'是否已被預訂此時克服了這個問題。但是所有這些檢查都是在軟件級別上完成的,那些對服務器的多重請求以及在程序中循環以執行與一個可能簡單的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

它剛剛找到我,我可能正在尋找像SQL循環中的東西。你可以選擇一個表並遍歷其中的每一行,並將它們中的一些傳遞到使用TSQL中的循環的結果表中? – IvanN

+0

可以檢查不在子查詢中的三列,但不是沒有理解您的要求拳頭。 – Tim3880

回答

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中的保留字。

+0

謝謝,這應該工作。我沒有真正使用這些字段名稱,這些名稱只是別名,只是爲了更清楚我想要顯示的內容。但感謝您的建議 – IvanN

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; 
相關問題