sql选择与列组合匹配的id

时间:2014-10-31 15:05:55

标签: sql sql-server

我有一个令牌表

  id | status
  ------------
  1  | taken
  1  | used
  1  | deleted
  2  | taken
  2  | deleted
  3  | taken

我需要计算使用或使用的令牌数量。 如果在未使用的情况下获取和删除令牌,则不应计算它。

所以sql会像......

 SELECT count(*) if the id's status is not (taken & deleted)

上面示例中所需的已使用令牌数为2,为

 id 1 has been taken used and deleted -> count it
 id 3 has been taken -> count it
 id 2 has been taken and deleted without being used -> do not count it

6 个答案:

答案 0 :(得分:1)

有点冗长但有效且仍然可读和可维护:

SELECT COUNT(DISTINCT id)
FROM dbo.Token t
WHERE EXISTS
(
    SELECT 1 FROM dbo.Token t1
    WHERE t.id = t1.id
    AND   t1.status = 'used'
)
OR
(
  EXISTS(
      SELECT 1 FROM dbo.Token t1
      WHERE t.id = t1.id
      AND   t1.status = 'taken'
  )
  AND NOT EXISTS(
      SELECT 1 FROM dbo.Token t1
      WHERE t.id = t1.id
      AND   t1.status = 'deleted'
  )
)

Demo

答案 1 :(得分:0)

试试这个:

SELECT SUM(CASE WHEN (CHARINDEX('used', data.status) > 0) OR (data.status = 'taken') THEN 1 ELSE 0 END) as [count]
FROM 
(
   SELECT DISTINCT id, (SELECT STUFF((SELECT Distinct ',' + status
                                          FROM        token a
                                             WHERE a.id = b.id
                                          FOR XML PATH (''))
                                     , 1, 1, '')) as status
    FROM token b     
) data

Demo

答案 2 :(得分:0)

使用聚合和having子句获取符合条件的ID列表:

SELECT id
FROM token t
GROUP BY id
HAVING SUM(case when status = 'taken' then 1 else 0 end) > 0 or
       SUM(case when status = 'used' then 1 else 0 end) > 0;

要获得计数,请使用子查询或CTE:

SELECT COUNT(*)
FROM (SELECT id
      FROM token t
      GROUP BY id
      HAVING SUM(case when status = 'taken' then 1 else 0 end) > 0 or
             SUM(case when status = 'used' then 1 else 0 end) > 0
     ) t

答案 3 :(得分:0)

你需要能够考虑所有这三个条件,所以一个天真的方法是将每个三个与一个案例陈述进行比较:

WITH grouped as
(
    select id from #uses group by id
)
select grouped.id, 
    used = 
        CASE WHEN used.id is not null THEN 'YES' 
            WHEN taken.id is not null and deleted.id is null THEN 'YES'
        ELSE 'NO'
        END
from grouped
left join #uses taken on grouped.id = taken.id
    and taken.use_status = 'taken'
left join #uses used on grouped.id = used.id
    and used.use_status = 'used'
left join #uses deleted on grouped.id = deleted.id
    and deleted.use_status = 'deleted'

只要满足条件,case语句就会停止,因此您只需要WHENELSE来满足条件。

这是一种天真的方法,并假设您每个ID只有一行并使用状态类型。如果情况并非如此,你必须做一些额外的工作。

答案 4 :(得分:0)

如果已经使用并使用了令牌 - >不要算数

SELECT
  SUM(DECODE(status, 'taken', 1, 0)) +
  SUM(DECODE(status, 'used', 1, 0)) -
  SUM(DECODE(status, 'deleted', 1, 0))
FROM
  token t
WHERE
  status <> 'used' OR
  EXISTS(SELECT 1 FROM token t2 WHERE t2.id = t.id and t2.status = 'deleted')

如果已经使用并使用了令牌 - &gt;算上它

SELECT
  COUNT(1)
FROM
  token t
WHERE
  status = 'taken' AND
  (
    EXISTS(SELECT 1 FROM token t2 WHERE t2.id = t.id and t2.status = 'used') OR
    NOT EXISTS(SELECT 1 FROM token t2 WHERE t2.id = t.id and t2.status = 'deleted')
  )

答案 5 :(得分:0)

回到这个问题,一个解决方案可能是使用Pivot

SELECT COUNT(id)
FROM (
     SELECT id, status FROM Token
) src
PIVOT
(
    COUNT(status) FOR status IN ([taken], [used], [deleted])
) pvt
WHERE (taken = 1 AND deleted = 0)OR (used = 1)

DEMO