【问题标题】:Different ways to query this search in SQL?在 SQL 中查询此搜索的不同方法?
【发布时间】:2012-09-09 20:34:01
【问题描述】:

我正在自学 MS-SQL,我正在尝试从这 3 个表中找到不同的方法来查找按地区分组的 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); 

查询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

【问题讨论】:

  • 您已包含用于创建数据库的脚本,但未包含用于获取所需值的脚本。您尝试查询什么?
  • 用这个来编辑你的问题比将查询粘贴到 cmets 中更好(前两个我已经为你这样做了)
  • 我知道这不能回答您的问题,但我想马上告诉您避免在列名中使用空格。它可能会导致麻烦。有些人使用下划线,但我更喜欢 Camel Case Notation en.wikipedia.org/wiki/CamelCase - 例如 [Shipping Number] 可以是 ShippingNumber,在编写查询时更容易键入,并且您的开发人员(如果有的话)不会想杀了你:D
  • 对不起,我不想再竖琴了,只是另一个建议 - 不要使用 DateTime,使用 MS 推荐的 DateTime2:msdn.microsoft.com/en-us/library/ms187819.aspx 甚至在 StackOverFlow stackoverflow.com/questions/1334143/…
  • @dyslexicanaboko 为什么 CamelCasers 首字母大写?他们不应该像这样大写吗? AndNotLikeThis?

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


【解决方案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 个不错的查询中。

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

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

  2. 可能应该删除 Claims 表中的 SubID。如果您将 ClaimID 作为 Foreign Key (FK) 放入 Enrollment 表中会更好。

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

  4. 对于使用 NULL 作为衡量某物是否已支付或未支付的良好指标,我有点怀疑。只有设计者会知道空字段意味着付费。为此,您最好使用默认值为零并标记为 NOT NULL 的位字段 - 这样它就永远不会为空。毕竟这将为您省去编写 case 语句的麻烦,您可以直接使用该位作为您的总和 例如:SUM(x.Paid)。此外,由于各种原因,列有时会被错误地标记为 NULL。

  5. 考虑将 Channel 和 Region 列完全拉出 Enrollment 表。用整数 PK 将它们放在他们自己的表中。您可以使用 ChannelID 和 RegionID 在任何需要的地方引用 PK。这样,如果名称需要更改,您就不必担心数据完整性问题(UPDATE Table SET NameCol = 'a' WHERE NameCol = 'b' -- 这可能会导致意外的重命名灾难。)

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

恭喜你主动学习了这些东西。这是无价的知识(除非你上大学,在这种情况下,它的价值约为 50K 或更差……学生贷款……叹息……)。

【讨论】:

    【解决方案2】:

    您需要将所有表连接在一起才能获得区域。此版本假定每个索赔最多有 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
    

    如果有多个,则计数将被取消,因为将计算每个电话号码而不是每个索赔。要解决此问题,请将两个总和更改为:

    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)
    

    【讨论】:

      【解决方案3】:

      试试这个

      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
      

      【讨论】:

        猜你喜欢
        • 2014-10-20
        • 1970-01-01
        • 2017-01-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-15
        • 1970-01-01
        相关资源
        最近更新 更多