sql join проблема с негативами - PullRequest
0 голосов
/ 20 июля 2009

Мне нужно выбрать данные из двух таблиц, используя соединение. Это довольно просто и здесь нет проблем. Проблема возникает, когда поле, к которому я присоединяюсь, используется как два отдельных внешних ключа (я не проектировал это). Поэтому поле идентификатора, к которому я присоединяюсь, является либо положительным, либо отрицательным числом.

Если это положительное число, оно относится к ID_1 в таблице table_2, если оно отрицательное, число относится к ID_2 в таблице table_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-оператор для обработки этих нечетных. Это все выполняется clr sql из C #. Добавление отдельной SqlCommand в код, скорее всего, замедлит процесс, поэтому я бы предпочел хранить все это в одной команде.

Ваш вклад приветствуется, спасибо:)

Ответы [ 8 ]

2 голосов
/ 20 июля 2009

Допустим, таблицы выглядят так:

Table1 (id INT, foo INT, fk INT)

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

... где fk может использоваться для поиска строки в Table2 с использованием id1, если положительное, и id2, если отрицательное.

Тогда вы можете сделать соединение следующим образом:

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)
2 голосов
/ 20 июля 2009

Самый простой способ - объедините эти таблицы, используя 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
1 голос
/ 20 июля 2009

попробуйте

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
1 голос
/ 20 июля 2009

Вы можете сделать что-то вроде этого, но только после представления конструктора схемы в 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

Помните ЛАРТ, это самая важная часть!

1 голос
/ 20 июля 2009

Это не будет очень производительным ... но тогда ничего не будет. Вам нужно преобразовать свой отрицательный ключ в положительный и условную логику для соединения. Как это:

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), но это лучшее, что вы можете сделать, учитывая обстоятельства.

0 голосов
/ 20 июля 2009
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 ...
0 голосов
/ 20 июля 2009

Применяя левые объединения ко второй таблице и используя функцию абсолютного значения, вы сможете выполнить то, что ищете:

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_1 и ID_2 не являются взаимоисключающими, вы получите 2 результата запроса.

0 голосов
/ 20 июля 2009

Это должно быть что-то вроде

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 ...

Не уверен, что я неправильно понял ваш вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...