0

困扰我的是,对于一个简单的查询,我必须写出如此多的子选择和 WITH 语句。

问题是:是否有关于如何简化具有子查询的查询的基本准则

这是我的查询:

WITH cte_min
     AS (SELECT a.client_id,
                a.specimen_source,
                a.received_date
         FROM   f_accession_daily a
                JOIN (SELECT DISTINCT f.client_id,
                                      f.received_date,
                                      f.accession_daily_key
                      FROM   F_ACCESSION_DAILY f
                             JOIN (SELECT CLIENT_ID,
                                          Min(received_date) MinRecDate
                                   FROM   F_ACCESSION_DAILY
                                   GROUP  BY CLIENT_ID) i
                               ON f.CLIENT_ID = i.CLIENT_ID
                                  AND f.RECEIVED_DATE = i.MinRecDate) b
                  ON a.ACCESSION_DAILY_KEY = b.ACCESSION_DAILY_KEY),
     cte_max
     AS (SELECT a.client_id,
                a.specimen_source,
                a.received_date
         FROM   f_accession_daily a
                JOIN (SELECT DISTINCT f.client_id,
                                      f.received_date,
                                      f.accession_daily_key
                      FROM   F_ACCESSION_DAILY f
                             JOIN (SELECT CLIENT_ID,
                                          Max(received_date) MaxRecDate
                                   FROM   F_ACCESSION_DAILY
                                   GROUP  BY CLIENT_ID) i
                               ON f.CLIENT_ID = i.CLIENT_ID
                                  AND f.RECEIVED_DATE = i.MaxRecDate) b
                  ON a.ACCESSION_DAILY_KEY = b.ACCESSION_DAILY_KEY),
     cte_est
     AS (SELECT DISTINCT client_id,
                         MLIS_DATE_ESTABLISHED
         FROM   D_CLIENT
         WHERE  REC_ACTIVE_FLG = 1
                AND MLIS_DATE_ESTABLISHED IS NOT NULL)
SELECT DISTINCT f.client_id,
                cmin.specimen_source,
                cmin.received_date,
                cmax.specimen_source,
                cmax.received_date,
                cest.MLIS_DATE_ESTABLISHED
FROM   F_ACCESSION_DAILY f
       LEFT JOIN cte_max cmax
         ON cmax.CLIENT_ID = f.CLIENT_ID
       LEFT JOIN cte_min cmin
         ON cmin.CLIENT_ID = f.CLIENT_ID
       LEFT JOIN cte_est cest
         ON cest.CLIENT_ID = f.CLIENT_ID 

我不一定要求您自己进行简化(尽管对此我将非常感激),而是要求您提供有关重写此查询以使其更加优雅的一般准则/指导。

4

3 回答 3

3

这看起来更好吗?

;WITH minmax AS (
SELECT client_id, specimen_source, received_date,
       RMin = row_number() over (partition by Client_id
                                 order by received_date, accession_daily_key),
       RMax = row_number() over (partition by Client_id
                                 order by received_date desc, accession_daily_key desc)
FROM F_ACCESSION_DAILY
)
SELECT f.client_id,
       max(case when rmin=1 then f.specimen_source end),
       max(case when rmin=1 then f.received_date end),
       max(case when rmax=1 then f.specimen_source end),
       max(case when rmax=1 then f.received_date end),
       D.MLIS_DATE_ESTABLISHED
FROM   minmax f
LEFT JOIN D_CLIENT D ON D.REC_ACTIVE_FLG = 1 AND D.MLIS_DATE_ESTABLISHED IS NOT NULL
WHERE 1 in (f.rmin, f.rmax)
GROUP BY f.client_id, D.MLIS_DATE_ESTABLISHED
于 2012-09-25T21:33:10.500 回答
1

虽然我不确定是否每个人都会认为这更简单和/或更容易阅读,但我会这样做:

WITH 
  cte_MaxMinRecvd As
(
    SELECT      CLIENT_ID,   
                Min(received_date) MinRecDate,
                Max(received_date) MaxRecDate
    FROM        F_ACCESSION_DAILY
    GROUP BY    CLIENT_ID
)
, cte_MaxMinDaily As
(
    SELECT      *
    FROM        F_ACCESSION_DAILY f
    JOIN        cte_MaxMinRecvd   i     ON  f.CLIENT_ID = i.CLIENT_ID
)
, cte_min AS 
(
    SELECT  a.client_id,
            a.specimen_source,
            a.received_date
    FROM    F_ACCESSION_DAILY a
    WHERE   EXISTS(
                    SELECT  *
                    FROM    cte_MaxMinDaily f
                    WHERE   f.RECEIVED_DATE       = f.MinRecDate
                      AND   a.ACCESSION_DAILY_KEY = f.ACCESSION_DAILY_KEY
                   )
)
, cte_max AS 
(
    SELECT  a.client_id,
            a.specimen_source,
            a.received_date
    FROM    f_accession_daily a
    WHERE   EXISTS(
                    SELECT  *
                    FROM    cte_MaxMinDaily f
                    WHERE   f.RECEIVED_DATE       = f.MinRecDate
                      AND   a.ACCESSION_DAILY_KEY = f.ACCESSION_DAILY_KEY
                   )
)
SELECT DISTINCT 
            f.client_id,
            cmin.specimen_source,
            cmin.received_date,
            cmax.specimen_source,
            cmax.received_date,
            cest.MLIS_DATE_ESTABLISHED
FROM        F_ACCESSION_DAILY f
LEFT JOIN   cte_max  cmax        ON  cmax.CLIENT_ID = f.CLIENT_ID
LEFT JOIN   cte_min  cmin        ON  cmin.CLIENT_ID = f.CLIENT_ID
LEFT JOIN   D_CLIENT cest        ON  cest.CLIENT_ID = f.CLIENT_ID 
                                 AND cest.REC_ACTIVE_FLG = 1
                                 AND cest.MLIS_DATE_ESTABLISHED IS NOT NULL

我所做的主要是

  1. 在适用的情况下,将大部分子查询转换为 CTE,
  2. 将 Min 和 Max 子查询合并在一起,并且
  3. 将 DISTINCT 子查询更改为 EXISTS 子查询,这样可以更简单(通常性能更好)

糟糕,我也按照 Blam 的建议摆脱了 cte_est CTE。

于 2012-09-25T21:10:13.383 回答
1

50 行报告 5 个值,在所有这些中只引用了两个表。

在第一个 CTE 中,您有 4 个连接(或虚拟连接)到同一个表,并且没有其他表涉及报告 3 列。不知道关键所以不能断定它可以减少。

如果一个 cte 没有多次引用,那么它不会导致更少的代码行。

一方面,这个 cte 可以用更少的代码替换。

cte_est
     AS (SELECT DISTINCT client_id,
                         MLIS_DATE_ESTABLISHED
         FROM   D_CLIENT
         WHERE  REC_ACTIVE_FLG = 1
                AND MLIS_DATE_ESTABLISHED IS NOT NULL)
...
cest.MLIS_DATE_ESTABLISHED
...
LEFT JOIN cte_est cest
         ON cest.CLIENT_ID = f.CLIENT_ID

减少到

D_CLIENT.MLIS_DATE_ESTABLISHED
...
LEFT JOIN  D_CLIENT 
       ON  D_CLIENT.CLIENT_ID = f.CLIENT_ID 
       AND D_CLIENT.REC_ACTIVE_FLG = 1
       AND D_CLIENT.MLIS_DATE_ESTABLISHED IS NOT NULL
于 2012-09-25T20:06:35.437 回答