【问题标题】:SQL Server - Dealing with a strange table relationshipSQL Server - 处理奇怪的表关系
【发布时间】:2017-06-15 02:37:23
【问题描述】:

我工作的公司转售数据,因此同一“单位”可能会被售出两次。我正在尝试进行盈利能力计算,但由于表格的设置方式而感到头疼。

基本上我们有两个表,我们称它们为 Data 和 Sale。

数据:

dataid  cost
1       $1.00
2       $2.00

销售:

saleid  dataid  price
1       1       $5.00
2       2       $3.00
3       2       $4.00

我需要做的是以仅在首次销售时计算成本的方式加入表格。像这样:

利润:

saleid  dataid  price  cost   profit
1       1       $5.00  $1.00  $4.00
2       2       $3.00  $2.00  $1.00
3       2       $4.00  $0.00  $4.00

我正在处理近十亿行,因此性能也是一个问题。我意识到表结构非常愚蠢,但重构数据库不是一种选择。有什么建议吗?

【问题讨论】:

  • “第一”是什么意思?在上升的saleid? SQL 表没有顺序。您的插图是有序的 SQL 结果集(查询结果)吗?它的排序来源是什么?

标签: sql sql-server database sql-server-2012 data-warehouse


【解决方案1】:

或者您可以尝试使用 row_number(),正如 Gordon Linoff 从上一个答案中建议的那样来确定首次销售。

数据:

    IF ( OBJECT_ID('tempdb..#TmpData') IS NOT NULL )
        BEGIN 
            DROP TABLE #TmpData
        END 

    CREATE TABLE #TmpData ( dataid INT, cost MONEY, )
    CREATE CLUSTERED INDEX IX_TmpData_dataid ON #TmpData (dataid)

    INSERT  INTO #TmpData
            ( dataid, cost )
    VALUES  ( 1, 1 ),
            ( 2, 2 )

    IF ( OBJECT_ID('tempdb..#TmpSale') IS NOT NULL )
        BEGIN 
            DROP TABLE #TmpSale
        END 

    CREATE TABLE #TmpSale
        (
          saleid INT ,
          dataid INT ,
          price MONEY
        )
    CREATE CLUSTERED INDEX IX_TmpSale ON #TmpSale (saleid)
    CREATE NONCLUSTERED INDEX IX_TmpSale_dataid ON #TmpSale (dataid)


    INSERT  INTO #TmpSale
            ( saleid, dataid, price )
    VALUES  ( 1, 1, 5 ),
            ( 2, 2, 3 ),
            ( 3, 2, 4 )

使用 CTE 和 row_number :

    ;WITH    PROFIT
              AS ( SELECT   d.dataid d_dataid ,
                            d.cost ,
                            s.saleid ,
                            s.dataid s_dataid ,
                            price ,
                            ROW_NUMBER() OVER ( PARTITION BY d.dataid ORDER BY s.saleid ) ctr
                   FROM     #TmpData D
                            JOIN #TmpSale S ON S.dataid = D.dataid
                 )
        SELECT  saleid ,
                d_dataid dataid ,
                price ,
                IIF(ctr = 1, cost, 0) cost ,
                IIF(ctr = 1, ( price - cost ), price) profit
        FROM    PROFIT
        OPTION (MAXRECURSION 32767)

结果:

    saleid      dataid      price   cost    profit
    ----------- ----------- ------- ------- --------
    1           1           5.00    1.00    4.00
    2           2           3.00    2.00    1.00
    3           2           4.00    0.00    4.00

【讨论】:

    【解决方案2】:

    这看起来真的很奇怪。您可以使用row_number()

    select s.*, coalesce(c.cost, 0) as cost,
           (s.price - coalesce(c.cost, 0)) as profit
    from (select s.*,
                 row_number() over (partition by s.dataid order by s.saleid) as seqnum
          from sales s
         ) s left join join
         cost c
         on c.dataid = s.dataid;
    

    我应该注意到,您确实希望在sales(dataid, saleid) 上建立索引以提高性能。

    【讨论】:

      【解决方案3】:

      请注意,问题与索引或性能无关。 因为你已经抛出了示例表结构。

      恕我直言,正确的索引将是,

      CREATE CLUSTERED INDEX IX_TmpData_dataid ON #TmpData (dataid)
      
      CREATE CLUSTERED INDEX IX_TmpSale ON #TmpSale (saleid)
      CREATE NONCLUSTERED INDEX IX_TmpSale_dataid ON #TmpSale (dataid)INCLUDE(profit)
      

      试试这个,

      select saleid, dataid,t4.price,(case when rn=1 then cost else 0 end)Cost 
      ,price-(case when rn=1 then cost else 0 end)Profit
      FROM(
      select a.saleid,a.dataid,a.price, d.cost
      ,ROW_NUMBER()over(PARTITION by d.dataid order by d.dataid)rn
           from #TmpSale a
      left join #TmpData d on a.dataid=d.dataid
      )t4
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-06-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多