2009-07-20 67 views
0

我需要使用連接從兩個表中選擇數據。這很簡單,在這裏沒有問題。當我加入的字段被用作兩個單獨的外鍵時(我沒有設計這個),問題就出現了。所以我加入的ID字段是正數或負數。帶負數的sql連接問題

如果它是一個正數,它與table_2表上的ID_1相關,如果它是負數,則該數字與table_2表上的ID_2相關。然而,ID_2將是一個正數(儘管它在外鍵中被存儲爲負數)。顯然,有沒有約束執行這些 - 所以在本質上並不是真正的外鍵:/

我使用的SQL是這樣的,是精爲正數:

select t1.Stuff, t2.MoreStuff from table_1 t1 
join table_2 t2 on t1.ID_1 = t2.ID_1 
where ... 

如何整合這種加入的負面影響。這甚至有可能嗎?理想情況下,我想根據需要更改桌子,但顯然這不是一個有效的選擇。我很好,真的卡住了。

我唯一的想法是一個單獨的sql語句來處理這些奇怪的。這一切都是由C#中的clr sql運行的。向代碼中添加一個單獨的SqlCommand可能會減慢速度,因此我寧願將它全部保存在一個命令中。

您的意見是值得歡迎的,謝謝:)

回答

2

比方說,表是這樣的:

Table1 (id INT, foo INT, fk INT) 

Table2 (id1 INT, id2 INT, bar VARCHAR(100)) 

...其中fk可用於使用id1如果正面和id2如果爲負查找一個行Table2

然後,你可以做如下連接:

SELECT T1.id, T1.foo, T2.bar 
FROM Table1 T1 INNER JOIN Table2 T2 
ON (T1.fk > 0 AND T2.id1 = T1.fk) 
    OR (T1.fk < 0 AND T2.id2 = - T1.fk) 
0

它必須是這樣的

select t1.Stuff, t2.MoreStuff from table_1 t1, table_2 t2 where (t1.ID_1 = t2.ID_1 OR t1.ID_1 = CONCAT("-",t2.ID_1)) where ... 

不知道如果我誤解你的問題。

+1

是什麼讓你覺得ID字段是文本? – 2009-07-20 14:16:51

0

通過應用左加入跨表中的兩個,並使用絕對值函數,你應該能夠完成你在找什麼:

SELECT t1.Stuff, isnull(t2.MoreStuff, t2_2.MoreStuff) 
FROM table_1 t1 
    LEFT JOIN table_2 t2  ON t1.ID_1 = t2.ID_1 
          AND t1.ID_1 > 0 
    LEFT JOIN table_2 t2_2 ON abs(t1.ID_2) = t2_2.ID_2 
          AND t1.ID_2 < 0 
WHERE 
    ... 

這裏需要說明的是,如果ID_1ID_2不是相互獨家你會得到2個查詢結果。

+0

很確定這是行不通的。不能用同名的兩個表來別名。 – Bill 2009-07-20 14:15:05

+0

錯過了,謝謝比爾 – 2009-07-20 14:17:16

2

Simpliest方式 - 使用UNION ALL連接這些表:

select t1.Stuff, t2.MoreStuff from table_1 t1 
join table_2 t2 on t1.ID_1 = t2.ID_1 
where t1._ID_1>0 
UNION ALL 
select t1.Stuff, t2.MoreStuff from table_1 t1 
join table_2 t2 on abs(t1.ID_1) = t2.ID_2 
where t1._ID_1<0 
+0

我提出了這個和加里麥吉爾的答案。兩者都應該工作。我很想知道UNION解決方案比複雜的IN子句解決方案更快還是更慢。 – Bill 2009-07-20 14:18:09

+0

我假設你實際上並不需要表中的所有行,在這種情況下,你需要一個WHERE子句。這使得UNION方法有點痛苦,因爲你需要複製WHERE部分。 – 2009-07-20 14:20:50

1

這會不會是非常高性能的......不過呢,什麼都不會。您需要將您的負面關鍵字轉換爲正面關鍵字,以及連接的條件邏輯。就像這樣:

select t1.Stuff, t2.MoreStuff 
from table_1 t1 
join table_2 t2 on (t1.ID_1 > 0 AND t1.ID_1 = t2.ID_1) 
    OR (t1.ID_1 <0 AND ABS(t1.ID_1) = t2.ID_2) 
where ... 

使用索引,因爲你正在改變t1.ID_1(與ABS功能)沒有機會,但它是你可以做鑑於這種情況最好的。

1

你可以做這樣的事情,但引入架構設計師一LART後才:

SELECT 
    t1.stuff, COALESCE(t2a.morestuff, t2b.morestuff) 
    FROM 
    table_1 t1 
    LEFT JOIN table_2 t2a ON (t1.id_1 > 0 AND t1.id_1 = t2a.id_1) 
    LEFT JOIN table_2 t2b ON (t1.id_1 < 0 AND t1.id_1 = -1 * t2b.id_2) 
    // etc 

另外,

SELECT 
    t1.stuff, t2.morestuff 
    FROM 
    table_1 t1 
    LEFT JOIN table_2 t2 ON (
     (t1.id_1 > 0 AND t1.id_1 = t2.id_1) 
     OR (t1.id_1 < 0 AND t1.id_1 = -1 * t2.id_2) 
    ) 
    // etc 

記住LART,這是最重要的部分!

0
select t1.Stuff, t2.MoreStuff from table_1 t1 
join table_2 t2 on t1.ID_1 = t2.ID_1 or -t1.ID_1 = t2.ID_2 
where ... 
1

試試這個

DECLARE @Table TABLE(
     ID INT, 
     ForeignKeyID INT 
) 

INSERT INTO @Table (ID,ForeignKeyID) SELECT 1, 1 
INSERT INTO @Table (ID,ForeignKeyID) SELECT 2, 2 
INSERT INTO @Table (ID,ForeignKeyID) SELECT 3, -1 
INSERT INTO @Table (ID,ForeignKeyID) SELECT 4, -2 

DECLARE @ForeignTable TABLE(
     ID_1 INT, 
     ID_2 INT, 
     Val VARCHAR(MAX) 
) 

INSERT INTO @ForeignTable (ID_1,ID_2,Val) SELECT 1, 11, '1' 
INSERT INTO @ForeignTable (ID_1,ID_2,Val) SELECT 2, 22, '2' 
INSERT INTO @ForeignTable (ID_1,ID_2,Val) SELECT 3, 1, '3' 
INSERT INTO @ForeignTable (ID_1,ID_2,Val) SELECT 3, 2, '4' 

SELECT * 
FROM @Table t INNER JOIN 
     @ForeignTable ft ON ABS(t.ForeignKeyID) = 
          CASE 
           WHEN t.ForeignKeyID > 0 
            THEN ft.ID_1 
           ELSE 
            ft.ID_2 
          END