SQL SelfJoin +左外连接日历

时间:2015-08-06 15:01:38

标签: sql database 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 ;

这将返回一组字段

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

基本上,如果在日历数据上找不到代码,请使用prev。

有任何建议/想法吗? 提前谢谢。

S上。

3 个答案:

答案 0 :(得分:1)

您需要使用cross join表格calender查询结果。像这样的东西

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 

答案 1 :(得分:1)

您可以尝试以下步骤:

  • 将此中间结果和“calendar”表定义为WITH语句
  • 的链
  • 执行“{calendar”表的LEFT JOIN和上面定义的中间结果(某些数据库需要指定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的值来自你问题中报告的原始中间结果,因为缺少值,我想你想要的确实是显示所有日历值而不是
  • 上述步骤的第三点可以通过执行原始问题中说明的相同技术获得。
  • 您需要在最终结果中指定顺序。

希望这有帮助!

答案 2 :(得分:0)

我通过创建LEFT JOIN(日历记录到结果记录)来管理:在这种情况下,我正在避免通过CROSS连接获得的笛卡尔积,并且所有产品都是重复的。 对于PRE-CODE,我想在Result表上使用自联接:

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;