SQL SelfJoin + Left Outer JOIN 日历

SQL SelfJoin + Left Outer JOIN Calendar

我收到了一个 SelfJoin 查询

;WITH t as 
(
SELECT
ROW_NUMBER() OVER (ORDER BY dbo.DIM_PROJECT_TECH_OBJ.FUNCTIONAL_LOCATION,DATEADD(ms, DATEDIFF(ms, '00:00:00', CONVERT(VARCHAR,REPLACE(dbo.FACT_MEASUREMENT.Doc_Time,'24:00:00','23:59:59'),102)), CONVERT(DATETIME, dbo.DIM_TIME_USAGE.DATE)) ASC) AS Rowy,
 dbo.FACT_MEASUREMENT.FACT_MEASUREMENT_KEY,
  dbo.FACT_MEASUREMENT.Doc_Number,
  dbo.FACT_MEASUREMENT.Created_By,
  dbo.FACT_MEASUREMENT.Text,
  dbo.FACT_MEASUREMENT.Doc_Time,
  dbo.FACT_MEASUREMENT.Date_Loaded,
  dbo.DIM_VC_MEASURE.VALUATION_CODE_AND_DESC,
  dbo.DIM_TIME_USAGE.DATE,
  dbo.DIM_PROJECT_TECH_OBJ.FUNCTIONAL_LOCATION,
  dbo.DIM_VC_MEASURE.VALUATION_CODE,
CONVERT(VARCHAR,REPLACE(dbo.FACT_MEASUREMENT.Doc_Time,'24:00:00','23:59:59'),102) AS TIME,
DATEADD(ms, DATEDIFF(ms, '00:00:00', CONVERT(VARCHAR,REPLACE(dbo.FACT_MEASUREMENT.Doc_Time,'24:00:00','23:59:59'),102)), CONVERT(DATETIME, dbo.DIM_TIME_USAGE.DATE)) AS DATUM
FROM
  dbo.DIM_PROJECT_TECH_OBJ INNER JOIN dbo.FACT_MEASUREMENT ON (dbo.FACT_MEASUREMENT.PROJECT_TECH_OBJ_KEY=dbo.DIM_PROJECT_TECH_OBJ.PROJECT_TECH_OBJ_KEY)
   INNER JOIN dbo.DIM_TIME_USAGE ON (dbo.FACT_MEASUREMENT.TIME_KEY=dbo.DIM_TIME_USAGE.TIME_KEY)
   INNER JOIN dbo.DIM_VC_MEASURE ON (dbo.DIM_VC_MEASURE.VALUATION_CODE_KEY=dbo.FACT_MEASUREMENT.VALUATION_CODE_KEY)
WHERE
   dbo.FACT_MEASUREMENT.Measurement_Position  = 'AVAILABILITY'
   AND
   dbo.DIM_PROJECT_TECH_OBJ.FUNCTIONAL_LOCATION IN ('XXX','YYY','ZZZ')
     )
select t.*, tprev.DATUM AS PRE_DATUM, tprev.VALUATION_CODE AS PRE_CODE, DATEDIFF (minute,tprev.DATUM, t.DATUM) AS DELTA_MIN
from t join
     t tprev
     on tprev.rowy = t.rowy - 1 AND tprev.FUNCTIONAL_LOCATION = t.FUNCTIONAL_LOCATION ;

这将return一组字段

FUNTIONAL LOC   DATUM   CODE    PRE_DATUM   PRE_CODE   (-> Other fields)
XXX             01/07/2015  A   06/06/2015  Y
XXX             05/07/2015  B   01/07/2015  A
XXX             10/07/2015  C   05/07/2015  B
YYY             03/07/2015  B   15/06/2015  K
YYY             09/07/2015  C   03/07/2015  B
YYY             15/07/2015  A   09/07/2015  C

现在我想创建一个带有日历(从 01/07 到 10/07 的图像)日期的外部连接并获得类似的东西:

FUNTIONAL LOC   DATUM   CODE    PRE_DATUM   PRE_CODE
XXX             01/07/2015  A   06/06/2015  Y
XXX             02/07/2015      06/06/2015  Y
XXX             03/07/2015      06/06/2015  Y
XXX             04/07/2015      06/06/2015  Y
XXX             05/07/2015  B   01/07/2015  A
XXX             06/07/2015      01/07/2015  A
XXX             07/07/2015      01/07/2015  A
XXX             08/07/2015      01/07/2015  A
XXX             09/07/2015      01/07/2015  A
XXX             10/07/2015  C   05/07/2015  B
YYY             01/07/2015      15/06/2015  K
YYY             02/07/2015      15/06/2015  K
YYY             03/07/2015  B   15/06/2015  K
YYY             09/07/2015  C   03/07/2015  B
YYY             10/07/2015      03/07/2015  B

基本上当在日历数据上找不到代码时使用上一个。

有suggestion/idea吗? 提前致谢。

S.

您需要 cross join 您的查询结果 calender table。像这样

WITH t
     AS (SELECT Row_number()
                  OVER (
                    ORDER BY Q2.FUNCTIONAL_LOCATION)    AS Rowy,
                Q1.FACT_MEASUREMENT_KEY,
                CONVERT(VARCHAR(255), Q1.Doc_Time, 102) AS TIME
         FROM   dbo.DIM_PROJECT_TECH_OBJ Q2
                INNER JOIN dbo.FACT_MEASUREMENT Q1
                        ON Q1.PROJECT_TECH_OBJ_KEY = Q2.PROJECT_TECH_OBJ_KEY
         WHERE  Q1.Measurement_Position = 'XXX'),
     result
     AS (SELECT t.*,
                tprev.time
         FROM   t
                LEFT JOIN t tprev
                       ON tprev.rowy = t.rowy - 1),
     date_cook
     AS (SELECT FUNTIONAL_LOC,
                c.dates,
                PRE_DATUM,
                PRE_CODE
         FROM   result r
                CROSS JOIN calender c
         WHERE  c.dates BETWEEN '2015-07-01' AND '2015-07-10')
SELECT dc.FUNTIONAL_LOC,
       dc.dates           AS DATUM,
       Isnull(r.code, '') AS code,
       dc.PRE_DATUM,
       dc.PRE_CODE
FROM   date_cook dc
       LEFT OUTER JOIN result r
                    ON dc.FUNTIONAL_LOC= r.FUNTIONAL_LOC
                       AND dc.dates = r.DATUM
                       AND dc.PRE_DATUM = r.PRE_DATUM
                       AND dc.PRE_CODE = r.PRE_CODE 

我通过创建 LEFT JOIN(日历记录到结果记录)进行了管理:在这种情况下,我避免了通过 CROSS 连接获得的笛卡尔积和所有重复项。 对于 PRE-CODE,我正在考虑对结果使用自连接 table:

WITH t as (
      SELECT ROW_NUMBER() OVER (ORDER BY Q2.FUNCTIONAL_LOCATION) AS Rowy,
             Q1.FACT_MEASUREMENT_KEY,
             CONVERT(VARCHAR(255), Q1.Doc_Time, 102) AS TIME
      FROM dbo.DIM_PROJECT_TECH_OBJ Q2 INNER JOIN
           dbo.FACT_MEASUREMENT Q1
           ON Q1.PROJECT_TECH_OBJ_KEY = Q2.PROJECT_TECH_OBJ_KEY
      WHERE Q1.Measurement_Position = 'XXX'
     )
select t.*, tprev.time
from t left join
     t tprev
     on tprev.rowy = t.rowy - 1;

您可以尝试以下步骤:

  • 将此中间结果和 "calendar" table 定义为 WITH 语句的链
  • 执行 "calendar" table 的 LEFT JOIN 和上面定义的中间结果(某些 DB 需要指定 LEFT OUTER JOIN
  • 对上述两个步骤的结果再次执行行编号连接技术

前两步示例:

WITH t as ( ... ),
t2 as ( select t.*, tprev.time
  from t left join
     t tprev
     on tprev.rowy = t.rowy - 1 ),
cal as ( ... )
SELECT *
FROM cal
LEFT JOIN t2 
ON cal.DATUM = t2.DATUM;

请注意:

  • 你原来问题的中间结果现在定义为t2
  • 在您模拟的最终结果中,您不能将 DATUM 的值保留为来自问题中报告的原始中间结果,因为缺少值,我想您确实想要显示所有日历取而代之的是
  • 可以通过执行与您在原始问题中说明的相同的技术来获得上述步骤的第三点。
  • 您需要在最终结果中指定顺序。

希望对您有所帮助!