2014-10-31 2 views
2

У меня есть токен таблицаSQL Select идентификатор, который соответствует комбинации столбца

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 

ответ

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

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

0

Использование агрегации и пункт having, чтобы получить список подходящих идентификаторов:

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 
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' 

Делом заявления остановится, когда условие выполнено, поэтому вам нужно только WHEN и ELSE для удовлетворения условий.

Это наивный подход, и предполагает, что у вас есть только одна строка для каждого идентификатора и тип статуса. Вы должны были бы выполнить дополнительную работу, если бы это было не так.

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

если маркер был принят и используется -> пересчитать

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