2011-10-06 42 views
4

試圖找到最好的方式來處理這個,由於某種原因,它真的讓我絆倒了。卡住這個聯盟/除了

我的數據是這樣的:

transaction_id(pk) decision_id(pk) accepted_ind  
A     1    NULL 
A     2    <blank> 
A     4    Y 
B     1    <blank> 
B     2    Y 
C     1    Y 
D     1    N 
D     2    O 
D     3    Y 
  1. 每一筆交易都保證有第1
  2. 可以有多個決策的可能性(假設的)類型的場景
  3. 接受可以有多個值或空白或NULL,但只有一個可以接受_ind = Y

我在嘗試寫一個查詢:

  1. 返回一行每個TRANSACTION_ID
  2. 返回的decision_id其中accepted_ind = Y,或者如果該事務沒有行accepted_ind = Y,然後用decision_id = 1返回行(無論的值)

我試過了: 1.使用邏輯「或」拉記錄,不斷得到重複。 2.使用聯合和除了但不能完全正確地獲得邏輯。

任何幫助表示讚賞。我不知道爲什麼這讓我非常沮喪!

亞當

回答

0

有可能是一個整潔的/更高效的查詢,但我認爲這將完成這項工作。它假設表名是Decision:

SELECT CASE 
     WHEN accepteddecision.transaction_id IS NOT NULL THEN 
     accepteddecision.transaction_id 
     ELSE firstdecision.transaction_id 
     END AS transaction_id, 
     CASE 
     WHEN accepteddecision.decision_id IS NOT NULL THEN 
     accepteddecision.decision_id 
     ELSE firstdecision.decision_id 
     END AS decision_id, 
     CASE 
     WHEN accepteddecision.accepted_ind IS NOT NULL THEN 
     accepteddecision.accepted_ind 
     ELSE firstdecision.accepted_ind 
     END AS accepted_ind 
FROM decision 
     LEFT OUTER JOIN (SELECT * 
         FROM decision AS accepteddecision 
         WHERE accepteddecision.accepted_ind = 'Y') AS 
         accepteddecision 
     ON accepteddecision.transaction_id = decision.transaction_id 
     LEFT OUTER JOIN (SELECT * 
         FROM decision AS firstdecision 
         WHERE firstdecision.decision_id = 1) AS firstdecision 
     ON firstdecision.transaction_id = decision.transaction_id 
GROUP BY accepteddecision.transaction_id, 
      firstdecision.transaction_id, 
      accepteddecision.decision_id, 
      firstdecision.decision_id, 
      accepteddecision.accepted_ind, 
      firstdecision.accepted_ind 
+0

子查詢不需要只是做一個而在你的JOIN例如'加入決定AcceptedDecision ON AcceptedDecision.transaction_id = Decision.transaction_id AND AcceptedDecision.accepted_ind ='Y'您也可以使用'COALESCE'而不是CASE語句 –

2

試試這個。基本上WHERE條款說:

凡接受=「Y」

有這個交易沒有接受行和decision_id = 1

SELECT Transaction_id, Decision_ID, Accepted_id 
FROM MyTable t 
WHERE Accepted_ind = 'Y' 
OR (NOT EXISTS (SELECT 1 FROM MyTable t2 
       WHERE Accepted_ind = 'Y' 
       and t2.Transaction_id = t.transaction_id) 
    AND Decision_id = 1) 
+0

謝謝!查詢完全有意義,並給我我正在尋找的確切結果!我相信我看了這麼長時間纔開始走錯路。 –

2

這種方法使用ROW_NUMBER(),因此只會工作在SQL Server 2005或更高版本上

我已修改您的示例數據,因爲它代表所有transaction_id都有Y指示器!

DECLARE @t TABLE ( 
    transaction_id NCHAR(1), 
    decision_id INT, 
    accepted_ind NCHAR(1) NULL 
) 

INSERT @t VALUES 
    ('A' , 1 , NULL), 
    ('A' , 2 , ''), 
    ('A' , 4 , 'Y'), 
    ('B' , 1 , ''), 
    ('B' , 2 , 'N'), -- change from your sample data 
    ('C' , 1 , 'Y'), 
    ('D' , 1 , 'N'), 
    ('D' , 2 , 'O'), 
    ('D' , 3 , 'Y') 

這裏是查詢本身:

SELECT transaction_id, decision_id, accepted_ind FROM ( 
SELECT transaction_id, decision_id, accepted_ind, 
    ROW_NUMBER() OVER (
     PARTITION BY transaction_id 
     ORDER BY 
      CASE 
       WHEN accepted_ind = 'Y' THEN 1 
       WHEN decision_id = 1 THEN 2 
       ELSE 3 
      END 
    ) rn 
FROM @t 
) Raw 
WHERE rn = 1 

結果:

transaction_id decision_id accepted_ind 
-------------- ----------- ------------ 
A    4   Y 
B    1    
C    1   Y 
D    3   Y 

ROW_NUMBER()節給出了一個 '優先' 每個標準你提到;我們然後ORDER BY挑選最好的,並採取第一行。

+0

這是我開始建立的。關於它的好處是你可以建立額外的排名參數。例如接受,比空白,然後第一 –

+0

謝謝!這工作得很好,我從來沒有考慮過這種方法,但我真的很喜歡它! –

0

出於興趣,下面使用作爲問題標題指定UNIONEXCEPT(加上JOIN):

WITH T AS (SELECT * FROM (
       VALUES ('A', 1, NULL), 
        ('A', 2, ''), 
        ('A', 4, 'Y'), 
        ('B', 1, ''), 
        ('B', 2, 'Y'), 
        ('C', 1, 'Y'), 
        ('D', 1, 'N'), 
        ('D', 2, 'O'), 
        ('D', 3, 'Y'), 
        ('E', 2, 'O'), -- smaple data extended 
        ('E', 1, 'N') -- smaple data extended 
      ) AS T (transaction_id, decision_id, accepted_ind) 
    ) 
SELECT * 
    FROM T 
WHERE accepted_ind = 'Y' 
UNION 
SELECT T.* 
    FROM (
     SELECT transaction_id 
      FROM T 
     WHERE decision_id = 1 
     EXCEPT 
     SELECT transaction_id 
      FROM T 
     WHERE accepted_ind = 'Y' 
     ) D 
     JOIN T 
      ON T.transaction_id = D.transaction_id 
      AND T.decision_id = 1;