4

在 Oracle 中,可以使用||获取多列中不同值的计数。操作员(无论如何,根据这个论坛帖子):

SELECT COUNT(DISTINCT ColumnA || ColumnB) FROM MyTable

有没有办法在 SQL Server 2008 中做到这一点?我正在尝试执行单个查询以返回一些组统计信息,但我似乎做不到。

例如,这是我要查询的值表:

AssetId MyId    TheirId   InStock
328     10      10        1
328     20      20        0
328     30      30        0
328     40      10        0
328     10      10        0
328     10      10        0
328     10      10        0
328     10      10        0

对于 AssetId #328,我想计算MyIdTheyId列中唯一 ID 的总数(4 = 10、20、30、40),以及InStock列中非零行的总数(1 ):

AssetId     TotalIds    AvailableIds
328         4           1

有没有办法以某种方式发挥这种魔力?

4

6 回答 6

2

您可以使用cross applyvalues

select T1.AssetId,
       count(distinct T2.ID) TotalIds,
       sum(case T2.InStock when 0 then 0 else 1 end) AvailableIds 
from YourTable as T1
  cross apply(values(T1.MyId, T1.InStock),
                    (T1.TheirId, 0)
             ) as T2(ID, InStock)
group by T1.AssetId  

SE-数据

或者您可以union all在子查询中执行。

select T.AssetId,
       count(distinct T.ID) TotalIds,
       sum(case T.InStock when 0 then 0 else 1 end) AvailableIds 
from (
     select AssetId, MyId as ID, InStock
     from YourTable
     union all
     select AssetID, TheirId, 0
     from YourTable
     ) as T
group by T.AssetId  
于 2012-08-12T09:54:45.670 回答
1

你可以得到这样的结果:

DECLARE @t TABLE (AssetId INT, MyId    INT, TheirId   INT, InStock INT)
INSERT @t
VALUES 
(328,10, 10,   1)
,(328,20, 20,   0)
,(328,30, 30,   0)
,(328,40, 10,   0)
,(328,10, 10,   0)
,(328,10, 10,   0)
,(328,10, 10,   0)
,(328,10, 10,   0)

;WITH a AS(
    SELECT  AssetId,
            COUNT(col) cnt
    FROM 
    (
            SELECT  MyId col, AssetId
            FROM    @t
            UNION
            SELECT  TheirId col, AssetId
            FROM    @t
    ) b
    GROUP BY AssetId
)

SELECT  a.AssetId,
        a.cnt TotalIds,
        SUM(CASE WHEN InStock <> 0 THEN 1 ELSE 0 END) AvailableIds
FROM    @t c
JOIN    a ON a.AssetId = c.AssetId
GROUP   BY a.AssetId, a.cnt

在公用表表达式(WITH代码块)中,“唯一性”是通过使用UNION丢弃重复值的运算符来保证的,这就是为什么COUNT(col)不需要像COUNT(DISTINCT col).

于 2012-08-12T07:55:40.440 回答
1

我认为这对你来说是一个很好的解决方案

SELECT COUNT(*)
FROM (SELECT DISTINCT Column1, Column2 
      FROM MyTable) A
于 2012-08-12T08:07:54.863 回答
1

您可以按照 Oracle 示例将这些值连接在一起(这就是 Oracle 查询所做的事情)。您只需先将值转换为字符:

select AssetId,
       count(distinct cast(MyId as varchar(8000))+','+cast(TheirId as varchar(8000)
            ) totalIds,
       count(distinct case when inStock> 0
                           then cast(MyId as varchar(8000))+','+cast(TheirId as varchar(8000)
             end) as AvailableIds
from t
group by Assetid

您也可以将其作为子查询进行:

select AssetId, count(*) as TotalIds,
       sum(case when inStock > 0 then 1 else 0 end) as AvailableIds
from (select AssetId, myId, theirId, max(inStock) as inStock
      from t
      group by AssetId, myId, theirId
     ) a
group by AssetId

“理论上”,我更喜欢第二种方法,因为它更基于集合。但是,如果您发现自己试图计算几个不同变量中的不同组合列,则字符串连接方法更实用。

于 2012-08-12T14:50:18.687 回答
0

选项1

select 
          AssetID, count(distinct MyId) As MyId, SUM(InStock) InStock
From T
Group By 
      AssetID

选项 #2 无 CTE

Select AssetID, count(MyId), sum(InStock) InStock From
(
    select 
            AssetID, MyId, SUM(InStock) InStock
    From MyTable
    Group By 
            AssetID, MyId
)K
Group by AssetID

选项 #3 与 CTE

;With Sub(AssetID, MyId, InStock)
As
(
    select 
            AssetID, MyId, SUM(InStock) InStock
    From MyTable
    Group By 
            AssetID, MyId
)

Select AssetID, count(MyId), sum(InStock) From
(
    Select * from Sub
)K
于 2012-08-12T09:19:47.680 回答
0

如果您不喜欢使用CTE's,可以尝试使用以下解决方案。它的要点是

  • 在单独的子查询中TotalID's为每个选择AssetID
  • 在单独的子查询中AvailableIDs为每个选择AssetID
  • JOIN两个子查询的结果产生最终结果。

语句原样适用于整个表。您可以通过向整个组添加适当的 where 子句来获取单个 AssetID 的结果。

SQL 语句

SELECT  a.AssetId, t.TotalIDs, a.AvailableIDs
FROM    (
            SELECT  AssetID, TotalIDs = COUNT(*) 
            FROM    (
                        SELECT  AssetID 
                        FROM    MyTable 
                        GROUP BY 
                                MyId, TheirID, AssetID
                    ) t 
            GROUP BY 
                    AssetID
        ) AS t
        INNER JOIN (
            SELECT  AssetID, AvailableIDs = SUM(InStock) 
            FROM    MyTable 
            GROUP BY 
                    AssetID
        ) AS a ON a.AssetId = t.AssetId

测试脚本

;WITH MyTable (AssetId, MyId, TheirId, InStock) AS (
    SELECT * FROM (VALUES 
        (328, 10, 10, 1)
        , (328, 20, 20, 0)
        , (328, 30, 30, 0)
        , (328, 40, 10, 0)
        , (328, 10, 10, 0)
        , (328, 10, 10, 0)
        , (328, 10, 10, 0)
        , (328, 10, 10, 0)
        , (329, 10, 10, 0)
        , (329, 10, 20, 1)
    ) AS a (b, c, d, e)
)
SELECT  a.AssetId, t.TotalIDs, a.AvailableIDs
FROM    (
            SELECT  AssetID, TotalIDs = COUNT(*) 
            FROM    (
                        SELECT  AssetID 
                        FROM    MyTable 
                        GROUP BY 
                                MyId, TheirID, AssetID
                    ) t 
            GROUP BY 
                    AssetID
        ) AS t
        INNER JOIN (
            SELECT  AssetID, AvailableIDs = SUM(InStock) 
            FROM    MyTable 
            GROUP BY 
                    AssetID
        ) AS a ON a.AssetId = t.AssetId
于 2012-08-12T09:48:03.630 回答