2

これがsqlfiddleの問題です

いくつかのテーブルが FULL OUTER JOINED になっています。この質問では、2 つのテーブルだけに単純化しました。FULL JOINS の理由は、プロダクション テーブルには一貫性のないさまざまなフィールドが多数あるためです。そのため、次の間で UNION ALL を実行しても機能しません。

create table dates1 
(
USERID INT,
[Date] datetime
)
insert into dates1
values
( 1, '01 jan 2012'),
( 2, '03 jan 2012')

create table dates2 
(
USERID INT,
[Date] datetime
)
insert into dates2
values
( 2, '01 jan 2012'),
( 4, '04 jan 2012')

各 USERID について、最小日付を見つける必要があります。これが試みです。プロダクションスクリプトでは4つまたは5つのテーブルが結合される可能性があるため、COALESCEを使用しました。

SELECT 
  COALESCE(x.USERID,y.USERID) USERID
  , CASE WHEN x.[Date] < Y.[DATE] 
        THEN x.[Date] 
        ELSE Y.[DATE] END [DATE]
FROM 
dates1 x 
FULL OUTER JOIN dates2 y 
    ON x.USERID = y.USERID

上記は次を返します。これは、User1 の最小日付を 2012 年 1 月 1 日にする必要があるため、ユーザー 1 にとっては間違っています。

これらの日付を見つけるためのスケーラブルなスクリプトは何ですか?

私が使ってきた厄介な解決策はこれです:

SELECT 
  COALESCE(x.USERID,y.USERID) USERID
  , CASE 
      WHEN ISNULL(x.[Date],'1 JAN 2020') < ISNULL(Y.[DATE],'1 JAN 2020') 
      THEN ISNULL(x.[Date],'1 JAN 2020') 
      ELSE ISNULL(Y.[DATE],'1 JAN 2020') 
  END [DATE]
FROM 
  dates1 x 
  FULL OUTER JOIN dates2 y 
     ON x.USERID = y.USERID

ここに画像の説明を入力

4

3 に答える 3

1

一方が NULL であるために比較が false になるケースを処理する必要があります。

CASE WHEN x.[Date] < Y.[DATE] OR Y.[DATE] IS NULL

もう少し簡単なことを試すこともできます。

SELECT userid, MIN(date) FROM
(SELECT userid, date FROM dates1
 UNION ALL SELECT userid, date FROM dates2
 -- ...
) AS x
GROUP BY userid
于 2012-06-18T16:21:30.803 に答える
1

このタイプのケース (min of min of min など) でコードの繰り返しCROSS APPLYを減らす(ただし、排除しない)ために使用する方法は次のとおりです...

CREATE FUNCTION min_datetime (datetime1 AS DATETIME, datetime2 AS DATETIME)
RETURNS TABLE
AS
RETURN
  SELECT CASE WHEN datetime1 < datetime2 THEN datetime1
              WHEN datetime1 > datetime2 THEN datetime2
              WHEN datetime1 IS NULL     THEN datetime2
                                         ELSE datetime1
         END AS val
GO;

SELECT
  COALESCE(a.id, b.id, c.id, d.id, e.id)                    as id,
  [min_datetime_d_e].val                                    as date,
  a.fields,  b.fields,  c.fields,  d.fields,  e.fields
FROM
                  a
  FULL OUTER JOIN b ON a.id = b.id
  FULL OUTER JOIN c ON b.id = COALESCE(a.id, b.id)
  FULL OUTER JOIN d ON c.id = COALESCE(a.id, b.id, c.id)
  FULL OUTER JOIN e ON d.id = COALESCE(a.id, b.id, c.id, d.id)
  CROSS APPLY dbo.min_datetime(a.date,               b.date) AS min_datetime_a_b
  CROSS APPLY dbo.min_datetime(min_datetime_a_b.val, c.date) AS min_datetime_b_c
  CROSS APPLY dbo.min_datetime(min_datetime_b_c.val, d.date) AS min_datetime_c_d
  CROSS APPLY dbo.min_datetime(min_datetime_c_d.val, e.date) AS min_datetime_d_e

編集: OPの投稿された回答のわずかなリファクタリング。

;WITH myCTE (UserID, [Date])
AS
  (
    SELECT UserID,[Date]FROM table1
    UNION ALL
    SELECT UserID,[Date]FROM table2
    UNION ALL
    SELECT UserID,[Date]FROM table3
  )
      , unique_by_user (UserID, [Date])
       (
              SELECT UserID, MIN([Date]) FROM myCTE GROUP BY UserID
       )
SELECT  
    u.UserID, u.[Date]
  , x.field1, x.field2
  , y.field3, y.field4
  , z.field5, z.field6
FROM
       unique_by_user u
  LEFT OUTER JOIN table2 x  
      ON u.USERID = x.USERID 
  LEFT OUTER JOIN table3 z  
      ON u.USERID = y.USERID 
  LEFT OUTER JOIN myCTE k  
      ON u.USERID = z.USERID 

上記の 2 つのオプションのパフォーマンスを比較すると興味深いでしょう。最初は、データを 2 回処理するコスト (CTE で 1 回、次に OUTER JOIN ですべてのレコードを再度結合する) のコストがこれを悪化させると考えていました。しかし、今はよくわかりません。テストして比較したいのですが、今日は時間がありません:)

于 2012-06-19T08:24:10.883 に答える
0

SQLfiddleでのライブコピー

質問は途中で少し変わりましたが、これは理想的ではありませんが、これが私が最終的に得たものです。

    create table table1 
    (
      UserID int,
      [Date] datetime,
      [field1] int,
      [field2] int
    )
    insert into table1
    values
    ( 1,'01 jan 2012',10,10),
    ( 2,'03 jan 2012',20,20)

    create table table2 
    (
      UserID int,
      [Date] datetime,
      [field3] int,
      [field4] int
    )
    insert into table2
    values
    ( 2,'01 jan 2012',30,30),
    ( 4,'04 jan 2012',40,40)


    create table table3 
    (
      UserID int,
      [Date] datetime,
      [field5] int,
      [field6] int
    )
    insert into table3
    values
    ( 2,'01 jan 2012',30,30),
    ( 4,'04 jan 2012',40,40)

これのSQL-これは事実上Aaronによって提唱されたアイデアですが、完全な外部結合にフィードするcteを使用するため、わずかに異なります。

;WITH myCTE (UserID, [Date])
AS
  (
    SELECT UserID,[Date]FROM table1 GROUP BY UserID,[Date] 
    UNION
    SELECT UserID,[Date]FROM table2 GROUP BY UserID,[Date] 
    UNION
    SELECT UserID,[Date]FROM table3 GROUP BY UserID,[Date]     
  )
      , myExtraCTE(UserID, [Date])

     AS
     (
     SELECT UserID, [Date] = MAX(Date) FROM myCTE GROUP BY UserID 
     ) 
SELECT  
  COALESCE(x.UserID,y.UserID, z.UserID ,k.UserID) USERID
  , MIN(k.[Date]) [Date]
  , SUM(ISNULL(x.field1,0.0)) field1
  , SUM(ISNULL(x.field2,0.0)) field2
  , SUM(ISNULL(y.field3,0.0)) field3
  , SUM(ISNULL(y.field4,0.0)) field4
  , SUM(ISNULL(z.field5,0.0)) field5
  , SUM(ISNULL(z.field6,0.0)) field6
FROM  
  table1 x  
FROM  
  table1 x  
  FULL OUTER JOIN table2 y  
      ON y.USERID  = x.USERID
  FULL OUTER JOIN table3 z  
      ON z.USERID  = coalesce(x.USERID,y.USERID)
  FULL OUTER JOIN myExtraCTE k  
      ON k.USERID  = coalesce(x.USERID,y.USERID,z.USERID)
GROUP BY
  COALESCE(x.UserID,y.UserID, z.UserID ,k.UserID)
于 2012-06-19T16:48:38.897 に答える