Соедините два разных стола - PullRequest
0 голосов
/ 21 января 2019

У меня есть следующий оператор SQL для запроса:

SELECT
    DATE '1900-01-01' + FLOOR("DDate" / 1000) * INTERVAL'1' YEAR+ (MOD("DDate", 1000) -1) * INTERVAL'1' DAY AS "Date",
    LTRIM((SUBSTR("NR8", -6)), '0') AS "Nr",
    CASE WHEN "tEnd" =240000 THEN '23:59:59' ELSE REPLACE(TO_CHAR("tEnd", '00,00,00'),',',':') END AS "End",
    REPLACE(TO_CHAR("zBegin", '00,00,00'),',',':') AS "tStart",
    "Doc1" AS "Doc",
    "Order" AS "Order"
FROM "MP002"."KKI1001"
WHERE   "DDate" >119000
    AND "tFact" = 1

ORDER BY "Date", "Order"

Поскольку это около 15 миллионов записей, я хотел бы получать только необходимые наборы данных. БД Oracle "KKI1100" содержит столбец "Doc1" и столбец "Тип". Однако теперь я хочу, чтобы все наборы данных только из «KKI1001», которые в «KKI1100» om столбец «Тип» содержат либо X, X1 или X2.

Как это должно быть реализовано? Используя соединение и предложение where? Или есть более элегантный метод?

Ответы [ 3 ]

0 голосов
/ 21 января 2019

Если бы я был на вашем месте, я бы просто присоединил второй стол к первому, вот так:

SELECT DATE '1900-01-01' + floor(k1."DDate" / 1000) * INTERVAL '1' YEAR + (MOD(k1."DDate", 1000) - 1) * INTERVAL '1' DAY AS "Date",
       ltrim((substr(k1."NR8", -6)), '0') AS "Nr",
       CASE
         WHEN k1."tEnd" = 240000 THEN
          '23:59:59'
         ELSE
          REPLACE(to_char(k1."tEnd", '00,00,00'), ',', ':')
       END AS "End",
       REPLACE(to_char(k1."zBegin", '00,00,00'), ',', ':') AS "tStart",
       k1."Doc1" AS "Doc",
       k1."Order" AS "Order"
FROM   "MP002"."KKI1001" k1
       INNER JOIN "KKI1100" k2 ON k1."Doc1" = k2."Doc2" AND k2."Type" IN ('X', 'X1', 'X2')
WHERE  k1."DDate" > 119000
AND    k1."tFact" = 1
ORDER  BY "Date",
          "Order";

Вы можете переместить предложение k2."Type" in ('X', 'X1', 'X2') down into the где`;на самом деле это не имеет значения для внутреннего объединения, где находится предикат фильтрации (это важно для внешних объединений, в зависимости от того, какие результаты вы ожидаете увидеть).

NB Я предполагаю, что KKI1100. "Doc1"это уникальный столбец.Если он не уникален, то я бы предложил использовать предикат exists, например:

SELECT DATE '1900-01-01' + floor(k1."DDate" / 1000) * INTERVAL '1' YEAR + (MOD(k1."DDate", 1000) - 1) * INTERVAL '1' DAY AS "Date",
       ltrim((substr(k1."NR8", -6)), '0') AS "Nr",
       CASE
         WHEN k1."tEnd" = 240000 THEN
          '23:59:59'
         ELSE
          REPLACE(to_char(k1."tEnd", '00,00,00'), ',', ':')
       END AS "End",
       REPLACE(to_char(k1."zBegin", '00,00,00'), ',', ':') AS "tStart",
       k1."Doc1" AS "Doc",
       k1."Order" AS "Order"
FROM   "MP002"."KKI1001" k1
WHERE  k1."DDate" > 119000
AND    k1."tFact" = 1
AND    EXISTS (SELECT NULL
               FROM   "KKI1100" k2
               WHERE  k2."Type" in ('X', 'X1', 'X2')
               AND    k2."Doc1" = k1."Doc1")
ORDER  BY "Date",
          "Order";
0 голосов
/ 21 января 2019

Непонятно, как связаны таблицы.Это по упомянутому столбцу Doc1 в обеих таблицах?В любом случае, вы, кажется, хотите предложение IN или EXISTS.Что-то вроде:

...
WHERE ddate >119000
AND tfact = 1
AND doc1 IN
(
  SELECT doc1
  FROM kki1100
  WHERE type IN ('X', 'X1', 'X2')
)
ORDER BY "Date", "Order";

У него есть критерии, к которым он относится: в предложении WHERE.Вы можете использовать EXISTS вместо IN.Я предпочитаю IN здесь из-за его простоты.

И когда дело доходит до соображений производительности, переписывание запроса должно быть последним, что приходит на ум.Мы бы предпочли предоставить соответствующие индексы.Я не знаю о селективности ваших критериев.Может быть, только tfact = 1 приводит к очень небольшим строкам?Или ddate >119000?Или только комбинация двух?Или это скорее ограничение на определенные записи KKI1100?Ну, вы можете предоставить множество индексов для каждого случая, затем посмотреть, какие из них используются, и отбросить остальные:

CREATE INDEX idx1 ON kki1001 (ddate, tfact, doc1);
CREATE INDEX idx2 ON kki1001 (tfact, ddate, doc1);
CREATE INDEX idx3 ON kki1001 (doc1, tfact, ddate);
CREATE INDEX idx4 ON kki1100 (doc1, type);
CREATE INDEX idx5 ON kki1100 (type, doc1);
0 голосов
/ 21 января 2019

Чтобы избежать предложения where in или повторного предложения OR, вы можете попробовать использовать внутреннее соединение в подзапросе для X1, X2, X3

SELECT
    DATE '1900-01-01' + FLOOR("DDate" / 1000) * INTERVAL'1' YEAR+ (MOD("DDate", 1000) -1) * INTERVAL'1' DAY AS "Date",
    LTRIM((SUBSTR("NR8", -6)), '0') AS "Nr",
    CASE WHEN "tEnd" =240000 THEN '23:59:59' ELSE REPLACE(TO_CHAR("tEnd", '00,00,00'),',',':') END AS "End",
    REPLACE(TO_CHAR("zBegin", '00,00,00'),',',':') AS "tStart",
    "Doc1" AS "Doc",
    "Order" AS "Order"
FROM "MP002"."KKI1001"
INNER JOIN (
  select 'X1' as type from dual 
  union 
  select 'X2' as type from dual 
  union 
  select 'X3' as type from dual 

) t on t.tpe = "KKI1001".type 
WHERE   "DDate" >119000
    AND "tFact" = 1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...