在SQL中查询此搜索的不同方法?

时间:2012-09-09 20:34:02

标签: sql sql-server sql-server-2008 join

我正在教自己MS-SQL,我正在尝试找到不同的方法来查找2012年按区域分组的2012年付费和未付索赔的数量。如果返回日期,如果返回的日期为空,则索赔未付,则支付索赔。

我会附上我运行的代码,但我不确定是否有更好的方法可以做到。

感谢。

以下是代码:

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); 

和Query1

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 

QUERY2

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; 

QUERY3

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

3 个答案:

答案 0 :(得分:1)

您需要将所有表连接在一起才能获得该区域。此版本假定每个声明的电话记录最多:

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

如果有多个,则计数将被关闭,因为每个电话将被计算而不是每个声明。要解决此问题,请将两个总和更改为:

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)

答案 1 :(得分:1)

很难回答这个问题,因为我看到了你在问什么,但是还有其他一些小问题导致你的查询困难。

我的回答
所以,在这里回答你的问题的核心是我会做什么,当且仅当我正确地解释你的表结构时(更多的是继续)。

我没有包括索赔的数量,因为这会甩掉数字。我已经包含了两个查询,即最终查询和细分查询。对于总和(因为你正在学习),我使用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

如果可以,尽可能避免使用Sub Selects。它们对性能不是很好,但当然有时候你无法避免它。

您的表结构/关系是执行此查询时遇到困难的根本原因。在查看结构后,我发现你正在复制数据(这是一个不可拒绝),而你在将细节全部拉入一个不错的查询时遇到了麻烦。

我看到的问题领域(以及一些友好的建议)

  1. 您将Claims表中的ClaimDate列复制到PhoneShip表。我不确定它们是否有不同的含义,但如果它是重复的 - 请避免这种情况。

  2. 可能应删除声明表中的SubID。如果将ClaimID作为Foreign Key(FK)放入注册表中会更好。

  3. 为Phoneship表提供自己的Primary Key(PK) - 它易于使用,除了ClaimID和ShippingNumber的组合外,每行都是唯一的。查看Table RelationshipsUnique Constraints

  4. 我有点不确定如何使用NULL作为是否支付或未付款的良好指标。只有设计者才会知道空字段意味着付费。为此目的最好使用位字段,默认值为零并标记为NOT NULL - 这样它永远不会为空。毕竟这将为您省去编写案例陈述的麻烦,您可以直接使用该位作为您的总和Ex:SUM(x.Paid)。此外,如果出于各种原因而不打算将列错误地标记为NULL。

  5. 考虑完全从“注册”表中提取“渠道”和“地区”列。使用Integer PK将它们放在自己的表中。您可以使用ChannelID和RegionID在任何需要的地方引用PK。这样,如果名称需要更改,您将不必担心数据完整性问题(UPDATE表SET NameCol ='a'WHERE NameCol ='b' - 这可能会导致意外的重命名灾难。)

  6. 将RegionID和ChannelID放入Claims表中。如果您按照上面的步骤2(在注册表中有一个ClaimID FK),现在您在注册表中不需要它。

  7. 恭喜你主动学习这些东西。这是非常宝贵的知识(除非你上大学,在这种情况下它值得大约50K或更差......学生贷款......叹息......)。

答案 2 :(得分: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