连接两个不同的表

时间:2019-01-21 09:47:30

标签: sql oracle

我有以下用于查询的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"

由于这大约是15mio记录,所以我只想接收必要的数据集。 Oracle数据库“ KKI1100”包含列“ Doc1”和列“ Type”。 但是,现在,我只希望来自“ KKI1001”的所有数据集,这些数据集在“ KKI1100”的“类型”列中包含X,X1或X2。

应如何实施? 使用联接和where子句? 还是有一种更优雅的方法?

3 个答案:

答案 0 :(得分:1)

如果我是你,我只是将第二个表与第一个表进行内部连接,就像这样:

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 where`子句;过滤谓词所在的内部联接实际上并不重要(外部联接则很重要,具体取决于您希望看到的结果)。

我假设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";

答案 1 :(得分:1)

目前还不清楚表之间的关系。是否在两个表中都提到了Doc1列?无论如何,您似乎想要一个INEXISTS子句。像这样:

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

答案 2 :(得分:0)

为避免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