2013-08-16 4 views
2

У меня есть эти таблицы в моей базе данных:SQL вопрос подзапрос с внутренним соединением

Tourist - это первая таблица

Tourist_ID - primary key 
name...etc... 

EXTRA_CHARGES

Extra_Charge_ID - primary key 
Extra_Charge_Description 
Amount 

Tourist_Extra_Charges

Tourist_Extra_Charge_ID 
Extra_Charge_ID - foreign key 
Tourist_ID - foreign key 

Так вот пример

Я один турист с Tourist_ID - 86. Этот турист с номером 86 имеет дополнительную плату с Extra_Charge_ID - 7 и Extra_charge_ID - 11;

Я стараюсь сделать запрос, чтобы я мог взять имя Туриста и все расходы в таблице EXTRA_CHARGES, что не принадлежит этому туристу.

Вот запрос, который я пытаюсь - но он ничего не возвращает.

SELECT 
    Tourist.Name 
    , EXTRA_CHARGES.Extra_Charge_Description 
    , EXTRA_CHARGES.Amount 
FROM 
    Tourist 
    INNER JOIN TOURIST_EXTRA_CHARGES 
     ON Tourist.Tourist_ID = TOURIST_EXTRA_CHARGES.Tourist_ID 
    INNER JOIN EXTRA_CHARGES 
     ON TOURIST_EXTRA_CHARGES.Extra_Charge_ID = EXTRA_CHARGES.Extra_Charge_ID 
WHERE 
    Tourist.Tourist_ID= 86 
    and EXTRA_CHARGES.Extra_Charge_ID NOT IN 
    ( SELECT Extra_Charge_ID 
     FROM TOURIST_EXTRA_CHARGES te 
     WHERE te.Tourist_ID = 86 
    ) 

Я, конечно, может получить только заряды с этим запросом

SELECT * FROM EXTRA_CHARGES e 
WHERE e.Extra_Charge_ID NOT IN 
(SELECT Extra_Charge_ID from TOURIST_EXTRA_CHARGES te 

    WHERE te.Tourist_ID = 86 
) 

, но я не могу найти способ, чтобы получить имя этого туриста

+0

вы можете показать выход вашего запроса, чтобы дать как больше понимания – zxc

ответ

1

Вы можете использовать два варианта, оба они почти одинаковы, но one may perform better than the other в зависимости от вашей СУБД.

Принципиальное обоих одно и то же, получить перекрестное соединение туристических и дополнительных расходов, так что вы имеете все дополнительные расходы для всех туристов, а затем использовать либо NOT EXISTS или LEFT JOIN/IS NULL устранить все дополнительные расходы, которые турист имеет:

SELECT Tourist.Name, 
     EXTRA_CHARGES.Extra_Charge_Description, 
     EXTRA_CHARGES.Amount 
FROM Tourist 
     CROSS JOIN EXTRA_CHARGES 
WHERE Tourist.Tourist_ID= 86 
AND  NOT EXISTS 
     ( SELECT 1 
      FROM TOURIST_EXTRA_CHARGES 
      WHERE TOURIST_EXTRA_CHARGES.Tourist_ID = Tourist.Tourist_ID 
      AND  TOURIST_EXTRA_CHARGES.Extra_Charge_ID = EXTRA_CHARGES.Extra_Charge_ID 
     ); 


SELECT Tourist.Name, 
     EXTRA_CHARGES.Extra_Charge_Description, 
     EXTRA_CHARGES.Amount 
FROM Tourist 
     CROSS JOIN EXTRA_CHARGES 
     LEFT JOIN TOURIST_EXTRA_CHARGES 
      ON TOURIST_EXTRA_CHARGES.Tourist_ID = Tourist.Tourist_ID 
      AND TOURIST_EXTRA_CHARGES.Extra_Charge_ID = EXTRA_CHARGES.Extra_Charge_ID 
WHERE Tourist.Tourist_ID = 86 
AND  TOURIST_EXTRA_CHARGES.Tourist_Extra_Charge_ID IS NULL; 

EDIT

с двумя критериями вы претендуете логически разные, вам нужно использовать два запроса, чтобы получить его.Во-первых, как и раньше, дополнительные расходы, которые турист не имеет, а второй для туристов, которые имеют все дополнительные расходы

SELECT Tourist.Name, 
     EXTRA_CHARGES.Extra_Charge_Description, 
     EXTRA_CHARGES.Amount 
FROM Tourist 
     CROSS JOIN EXTRA_CHARGES 
     LEFT JOIN TOURIST_EXTRA_CHARGES 
      ON TOURIST_EXTRA_CHARGES.Tourist_ID = Tourist.Tourist_ID 
      AND TOURIST_EXTRA_CHARGES.Extra_Charge_ID = EXTRA_CHARGES.Extra_Charge_ID 
WHERE Tourist.Tourist_ID = 1 
AND  TOURIST_EXTRA_CHARGES.Tourist_Extra_Charge_ID IS NULL 
UNION ALL 
SELECT Tourist.Name, 
     NULL, 
     NULL 
FROM Tourist 
     CROSS JOIN EXTRA_CHARGES 
     LEFT JOIN TOURIST_EXTRA_CHARGES 
      ON TOURIST_EXTRA_CHARGES.Tourist_ID = Tourist.Tourist_ID 
      AND TOURIST_EXTRA_CHARGES.Extra_Charge_ID = EXTRA_CHARGES.Extra_Charge_ID 
WHERE Tourist.Tourist_ID = 1 
GROUP BY Tourist.Name 
HAVING COUNT(*) = COUNT(TOURIST_EXTRA_CHARGES.Tourist_Extra_Charge_ID); 

Example on SQL Fiddle

+0

в обоих направлениях отлично работает –

+0

, как whathappens в первом случае, когда у туриста есть все расходы, поэтому запрос не будет возвращать строку. но мне нужно имя - даже если у них нет лишних зарядов –

1

Вы можете включать в себя название туристического (для Tourist_ID = 86) в качестве подзапроса в операторе выбора:

SELECT (SELECT Tourist.Name FROM Tourist WHERE Tourist_ID=86) TouristName, e.* 
FROM EXTRA_CHARGES e 
WHERE e.Extra_Charge_ID NOT IN 
     (SELECT Extra_Charge_ID 
     FROM TOURIST_EXTRA_CHARGES te 
     WHERE te.Tourist_ID = 86 
     ) 
+0

Эй, это работает, но когда я получаю имя в столбце - на нем написано «no column name». Вы знаете, как его получить. –

+1

Возможно, вы опустили имя столбца. Напишите как '(SELECT ....) AS TouristName' –

+0

Да, я так устал, что я действительно опустил его :) Thans –

0

Просто используйте INNER JOIN ... ON .. <> ...

SELECT 
    Tourist.Name 
    , EXTRA_CHARGES.Extra_Charge_Description 
    , EXTRA_CHARGES.Amout 
FROM 
    Tourist 
    INNER JOIN TOURIST_EXTRA_CHARGES 
     ON Tourist.Tourist_ID <> TOURIST_EXTRA_CHARGES.Tourist_ID 
    INNER JOIN EXTRA_CHARGES 
     ON TOURIST_EXTRA_CHARGES.Extra_Charge_ID = EXTRA_CHARGES.Extra_Charge_ID 
WHERE 
    Tourist.Tourist_ID= 86 

Смотрите здесь: http://sqlfiddle.com/#!2/28665/2

1

Вы можете попробовать это, более эффективно:

SELECT t.Name 
FROM Tourist t JOIN 
(SELECT * FROM EXTRA_CHARGES e 
JOIN TOURIST_EXTRA_CHARGE tec ON e.Extra_Charge_ID = tec.Extra_Charge_ID AND tec.TOURIST_EXTRA_CHARGES != 86) 
WHERE t.Tourist_ID = 86 

кстати. вам не нужен столбец Tourist_Extra_Charge_ID в Tourist_Extra_Charges

+0

Я думал, что OP также требует столбцов EXTRA_CHARGES с результатом. –

Смежные вопросы