1

私は MS-SQL を独学しており、これらの 3 つのテーブルから地域別にグループ化された 2012 年の有償および未払の請求の数を見つけるためのさまざまな方法を見つけようとしています。返された日付がある場合、返された日付が null の場合、請求は未払いであり、請求は支払われます。

実行したコードを添付しますが、より良い方法があるかどうかはわかりません。

ありがとう。

コードは次のとおりです。

SET dateformat ymd;

CREATE TABLE Claims
  (
     ClaimID      INT,
     SubID        INT,
     [Claim Date] DATETIME
  );

CREATE TABLE Phoneship
  (
     ClaimID           INT,
     [Shipping Number] INT,
     [Claim Date]      DATETIME,
     [Ship Date]       DATETIME,
     [Returned Date]   DATETIME
  );

CREATE TABLE Enrollment
  (
     SubID           INT,
     Enrollment_Date DATETIME,
     Channel         NVARCHAR(255),
     Region          NVARCHAR(255),
     Status          FLOAT,
     Drop_Date       DATETIME
  );

INSERT INTO [Phoneship]
            ([ClaimID],
             [Shipping Number],
             [Claim Date],
             [Ship Date],
             [Returned Date])
VALUES     (102,
            201,
            '2011-10-13 00:00:00',
            '2011-10-14 00:00:00',
            NULL);

INSERT INTO [Phoneship]
            ([ClaimID],
             [Shipping Number],
             [Claim Date],
             [Ship Date],
             [Returned Date])
VALUES     (103,
            202,
            '2011-11-02 00:00:00',
            '2011-11-03 00:00:00',
            '2011-11-20 00:00:00');

INSERT INTO [Phoneship]
            ([ClaimID],
             [Shipping Number],
             [Claim Date],
             [Ship Date],
             [Returned Date])
VALUES     (103,
            203,
            '2011-11-02 00:00:00',
            '2011-11-22 00:00:00',
            NULL);

INSERT INTO [Phoneship]
            ([ClaimID],
             [Shipping Number],
             [Claim Date],
             [Ship Date],
             [Returned Date])
VALUES     (105,
            204,
            '2012-01-16 00:00:00',
            '2012-01-17 00:00:00',
            NULL);

INSERT INTO [Phoneship]
            ([ClaimID],
             [Shipping Number],
             [Claim Date],
             [Ship Date],
             [Returned Date])
VALUES     (106,
            205,
            '2012-02-15 00:00:00',
            '2012-02-16 00:00:00',
            '2012-02-26 00:00:00');

INSERT INTO [Phoneship]
            ([ClaimID],
             [Shipping Number],
             [Claim Date],
             [Ship Date],
             [Returned Date])
VALUES     (106,
            206,
            '2012-02-15 00:00:00',
            '2012-02-27 00:00:00',
            '2012-03-06 00:00:00');

INSERT INTO [Phoneship]
            ([ClaimID],
             [Shipping Number],
             [Claim Date],
             [Ship Date],
             [Returned Date])
VALUES     (107,
            207,
            '2012-03-12 00:00:00',
            '2012-03-13 00:00:00',
            NULL);

INSERT INTO [Phoneship]
            ([ClaimID],
             [Shipping Number],
             [Claim Date],
             [Ship Date],
             [Returned Date])
VALUES     (108,
            208,
            '2012-05-11 00:00:00',
            '2012-05-12 00:00:00',
            NULL);

INSERT INTO [Phoneship]
            ([ClaimID],
             [Shipping Number],
             [Claim Date],
             [Ship Date],
             [Returned Date])
VALUES     (109,
            209,
            '2012-05-13 00:00:00',
            '2012-05-14 00:00:00',
            '2012-05-28 00:00:00');

INSERT INTO [Phoneship]
            ([ClaimID],
             [Shipping Number],
             [Claim Date],
             [Ship Date],
             [Returned Date])
VALUES     (109,
            210,
            '2012-05-13 00:00:00',
            '2012-05-30 00:00:00',
            NULL);

INSERT INTO [Claims]
            ([ClaimID],
             [SubID],
             [Claim Date])
VALUES     (101,
            12345678,
            '2011-03-06 00:00:00');

INSERT INTO [Claims]
            ([ClaimID],
             [SubID],
             [Claim Date])
VALUES     (102,
            12347190,
            '2011-10-13 00:00:00');

INSERT INTO [Claims]
            ([ClaimID],
             [SubID],
             [Claim Date])
VALUES     (103,
            12348723,
            '2011-11-02 00:00:00');

INSERT INTO [Claims]
            ([ClaimID],
             [SubID],
             [Claim Date])
VALUES     (104,
            12349745,
            '2011-11-09 00:00:00');

INSERT INTO [Claims]
            ([ClaimID],
             [SubID],
             [Claim Date])
VALUES     (105,
            12347190,
            '2012-01-16 00:00:00');

INSERT INTO [Claims]
            ([ClaimID],
             [SubID],
             [Claim Date])
VALUES     (106,
            12349234,
            '2012-02-15 00:00:00');

INSERT INTO [Claims]
            ([ClaimID],
             [SubID],
             [Claim Date])
VALUES     (107,
            12350767,
            '2012-03-12 00:00:00');

INSERT INTO [Claims]
            ([ClaimID],
             [SubID],
             [Claim Date])
VALUES     (108,
            12350256,
            '2012-05-11 00:00:00');

INSERT INTO [Claims]
            ([ClaimID],
             [SubID],
             [Claim Date])
VALUES     (109,
            12347701,
            '2012-05-13 00:00:00');

INSERT INTO [Claims]
            ([ClaimID],
             [SubID],
             [Claim Date])
VALUES     (110,
            12350256,
            '2012-05-15 00:00:00');

INSERT INTO [Claims]
            ([ClaimID],
             [SubID],
             [Claim Date])
VALUES     (111,
            12350767,
            '2012-06-30 00:00:00');

INSERT INTO [Enrollment]
            ([SubID],
             [Enrollment_Date],
             [Channel],
             [Region],
             [Status],
             [Drop_Date])
VALUES     (12345678,
            '2011-01-05 00:00:00',
            'Retail',
            'Southeast',
            1,
            NULL);

INSERT INTO [Enrollment]
            ([SubID],
             [Enrollment_Date],
             [Channel],
             [Region],
             [Status],
             [Drop_Date])
VALUES     (12346178,
            '2011-03-13 00:00:00',
            'Indirect Dealers',
            'West',
            1,
            NULL);

INSERT INTO [Enrollment]
            ([SubID],
             [Enrollment_Date],
             [Channel],
             [Region],
             [Status],
             [Drop_Date])
VALUES     (12346679,
            '2011-05-19 00:00:00',
            'Indirect Dealers',
            'Southeast',
            0,
            '2012-03-15 00:00:00');

INSERT INTO [Enrollment]
            ([SubID],
             [Enrollment_Date],
             [Channel],
             [Region],
             [Status],
             [Drop_Date])
VALUES     (12347190,
            '2011-07-25 00:00:00',
            'Retail',
            'Northeast',
            0,
            '2012-05-21 00:00:00');

INSERT INTO [Enrollment]
            ([SubID],
             [Enrollment_Date],
             [Channel],
             [Region],
             [Status],
             [Drop_Date])
VALUES     (12347701,
            '2011-08-14 00:00:00',
            'Indirect Dealers',
            'West',
            1,
            NULL);

INSERT INTO [Enrollment]
            ([SubID],
             [Enrollment_Date],
             [Channel],
             [Region],
             [Status],
             [Drop_Date])
VALUES     (12348212,
            '2011-09-30 00:00:00',
            'Retail',
            'West',
            1,
            NULL);

INSERT INTO [Enrollment]
            ([SubID],
             [Enrollment_Date],
             [Channel],
             [Region],
             [Status],
             [Drop_Date])
VALUES     (12348723,
            '2011-10-20 00:00:00',
            'Retail',
            'Southeast',
            1,
            NULL);

INSERT INTO [Enrollment]
            ([SubID],
             [Enrollment_Date],
             [Channel],
             [Region],
             [Status],
             [Drop_Date])
VALUES     (12349234,
            '2012-01-06 00:00:00',
            'Indirect Dealers',
            'West',
            0,
            '2012-02-14 00:00:00');

INSERT INTO [Enrollment]
            ([SubID],
             [Enrollment_Date],
             [Channel],
             [Region],
             [Status],
             [Drop_Date])
VALUES     (12349745,
            '2012-01-26 00:00:00',
            'Retail',
            'Northeast',
            0,
            '2012-04-15 00:00:00');

INSERT INTO [Enrollment]
            ([SubID],
             [Enrollment_Date],
             [Channel],
             [Region],
             [Status],
             [Drop_Date])
VALUES     (12350256,
            '2012-02-11 00:00:00',
            'Retail',
            'Southeast',
            1,
            NULL);

INSERT INTO [Enrollment]
            ([SubID],
             [Enrollment_Date],
             [Channel],
             [Region],
             [Status],
             [Drop_Date])
VALUES     (12350767,
            '2012-03-02 00:00:00',
            'Indirect Dealers',
            'West',
            1,
            NULL);

INSERT INTO [Enrollment]
            ([SubID],
             [Enrollment_Date],
             [Channel],
             [Region],
             [Status],
             [Drop_Date])
VALUES     (12351278,
            '2012-04-18 00:00:00',
            'Retail',
            'Midwest',
            1,
            NULL);

INSERT INTO [Enrollment]
            ([SubID],
             [Enrollment_Date],
             [Channel],
             [Region],
             [Status],
             [Drop_Date])
VALUES     (12351789,
            '2012-05-08 00:00:00',
            'Indirect Dealers',
            'West',
            0,
            '2012-07-04 00:00:00');

INSERT INTO [Enrollment]
            ([SubID],
             [Enrollment_Date],
             [Channel],
             [Region],
             [Status],
             [Drop_Date])
VALUES     (12352300,
            '2012-06-24 00:00:00',
            'Retail',
            'Midwest',
            1,
            NULL);

INSERT INTO [Enrollment]
            ([SubID],
             [Enrollment_Date],
             [Channel],
             [Region],
             [Status],
             [Drop_Date])
VALUES     (12352811,
            '2012-06-25 00:00:00',
            'Retail',
            'Southeast',
            1,
            NULL); 

そしてクエリ1

SELECT Count(ClaimID)                       AS 'Paid Claim',
       (SELECT Count(ClaimID)
        FROM   dbo.phoneship
        WHERE  [returned date] IS NOT NULL) AS 'Unpaid Claim'
FROM   dbo.Phoneship
WHERE  [Returned Date] IS NULL
GROUP  BY claimid 

クエリ2

SELECT Count(*)                             AS 'Paid Claims',
       (SELECT Count(*)
        FROM   dbo.Phoneship
        WHERE  [Returned Date] IS NOT NULL) AS 'Unpaid Claims'
FROM   dbo.Phoneship
WHERE  [Returned Date] IS NULL; 

クエリ3

Select Distinct(C.[Shipping Number]), Count(C.ClaimID) AS 'COUNT ClaimID', 
        A.Region, A.SubID 
From dbo.HSEnrollment A 
Inner Join dbo.Claims B On A.SubId = B.SubId 
Inner Join dbo.Phoneship C On B.ClaimID = C.ClaimID 
Where C.[Returned Date] IS NULL 
Group By A.Region, A.Subid, C.ClaimID, C.[Shipping Number] Order By A.Region
4

3 に答える 3

1

リージョンを取得するには、すべてのテーブルを結合する必要があります。このバージョンでは、各請求に対して最大でも Phoneship レコードがあると想定しています。

SELECT e.region, count(*) as numclaims,
       sum(case when ps.ReturnedDate is not null then 1 else 0 end) AS 'Paid Claim',
       sum(case when ps.ReturnedDate is null then 1 else 0 end) AS 'Unpaid Claim'
FROM   claims c join
       enrollment e
       on c.sub_id = e.sub_id left outer join
       Phoneship ps
       on ps.claimid = c.claimdid
WHERE  [Returned Date] IS NULL
GROUP  BY e.region

複数ある場合は、各クレームではなく各電話番号がカウントされるため、カウントはオフになります。これを修正するには、2 つの合計を次のように変更します。

count(distinct case when ps.ReturnedDate is not null then c.claimid end)
count(distinct case when ps.ReturnedDate is null then c.claimid end)
于 2012-09-09T20:52:08.920 に答える
1

あなたが何を求めているかはわかりますが、クエリの問題につながる他のさまざまな小さな問題があるため、この質問に答えるのは難しいです.

私の答え
したがって、ここであなたの質問の核心に答えるために、私があなたのテーブル構造を適切に解釈している場合にのみ、私は何をしますか (それについてはさらに説明します)。

クレームの数は含めませんでした。最終クエリとブレークダウン クエリの 2 つのクエリを含めました。合計の合計については (学習中のため)、WITH ROLLUP を使用して、グループ化された各列の合計を取得しました。

SELECT 
    e.Region,
    paid = SUM(CASE WHEN p.[Returned Date] IS NULL THEN 1 ELSE 0 END),
    unpaid = SUM(CASE WHEN p.[Returned Date] IS NULL THEN 0 ELSE 1 END)
FROM claims c
    INNER JOIN enrollment e
        ON e.SubID = c.SubID
    INNER JOIN phoneship p
        ON p.ClaimID = c.ClaimID
GROUP BY e.Region
WITH ROLLUP

ブレークダウン
これは、内部仮想テーブル (結果テーブル - 結果セットなど) のサブ選択を利用したブレーク ダウン クエリです。ポイントを示すために意図的にこれを行いました。

SELECT 
    x.Region,
    -- if the Returned Date is null then add 1, otherwise add 0
    paid = SUM(CASE WHEN x.ReturnedDate IS NULL THEN 1 ELSE 0 END),
    -- if the Returned Date is null then add 0, otherwise add 1
    unpaid = SUM(CASE WHEN x.ReturnedDate IS NULL THEN 0 ELSE 1 END)
FROM
(
-- Run this inner query to see what data you are actually working with
-- for your grouping/sums
SELECT 
    c.ClaimID,
    c.SubID,
    E = '#', -- This is just a separator
    e_SubID = e.SubID, -- This is equivalent to saying e.SubID AS e_SubID
    e.Region,
    P = '#', -- This is just a separator
    p_ClaimID = p.ClaimID,
    ShippingNo = p.[Shipping Number], -- Getting rid of those nasty spaces
    ReturnedDate = p.[Returned Date]
FROM claims c
    INNER JOIN enrollment e
        ON e.SubID = c.SubID
    -- Initially this was a LEFT JOIN but you are missing Claims in your 
    -- Phoneship table which will produce bogus results, therefore the
    -- INNER JOIN will filter out any rows that don't match
    INNER JOIN phoneship p
        ON p.ClaimID = c.ClaimID
) as x
GROUP BY x.Region
WITH ROLLUP

サブセレクトは可能な限り避けてください。性能的にはあまり良くありませんが、もちろん避けられない場合もあります。

テーブルの構造/関係が、このクエリの実行が困難な根本原因です。構造を確認したところ、データを複製しており (これはノー ノーです)、詳細をすべて 1 つの適切なクエリにまとめるのに問題があることがわかりました。

私が見た問題領域 (およびいくつかの親切なアドバイス)

  1. Claims テーブルの ClaimDate 列を PhoneShip テーブルに複製しました。それらの意味が異なるかどうかはわかりませんが、重複している場合は避けてください。

  2. Claims テーブルにある SubID は、おそらく削除する必要があります。ClaimID を外部キー(FK) として Enrollment テーブルに入れるとよいでしょう。

  3. Phoneship テーブルに独自の主キー(PK) を与えます。これは使いやすく、ClaimID と ShippingNumber の組み合わせを除いて各行を一意にします。Table RelationshipsUnique Constraintsを調べてください。

  4. 何かが支払われたか支払われていないかを示す良い指標として NULL を使用することについては、少し疑問があります。null フィールドが有料であることを知っているのは設計者だけです。この目的のために、デフォルト値がゼロで、NOT NULL としてマークされたビット フィールドを使用する方がよい場合があります。これにより、case ステートメントを記述する手間を省くことができます。例: SUM(x.Paid) のように、ビットを合計に直接使用できます。また、さまざまな理由で意図されていない場合でも、列が誤って NULL としてマークされることがあります。

  5. Enrollment テーブルから Channel 列と Region 列を完全に引き出すことを検討してください。それらを整数 PK を使用して独自のテーブルに配置します。ChannelID と RegionID を使用して、必要に応じてどこでも PK を参照できます。こうすれば、名前を変更する必要がある場合でも、データの整合性の問題について心配する必要はありません (UPDATE Table SET NameCol = 'a' WHERE NameCol = 'b' -- これにより、意図しない名前変更の災害が発生する可能性があります)。

  6. RegionID と ChannelID を Claims テーブルに入れます。上記の手順 2 に従う場合は、登録テーブルで必要ありません (登録テーブルに ClaimID FK がある場合)。

このようなことを学ぶために率先して取り組んでくれてありがとう。それは非常に貴重な知識です (大学に行かない限り、その場合は約 50K またはそれ以下の価値があります... 学生ローン... ため息...)。

于 2012-09-10T03:33:06.123 に答える
0

これを試して

SELECT e.Region, COUNT(c.SubID) TotalClaims, COUNT(p.[returned date]) UnpaidClaims, COUNT(c.SubID)-COUNT(p.[returned date]) PaidClaims
FROM
    Claims c
    INNER JOIN enrollment e ON c.SubID = e.SubID
    INNER JOIN phoneship p ON p.ClaimID = c.ClaimID
GROUP BY e.Region
于 2012-09-10T05:51:39.427 に答える