簡體   English   中英

SQL SERVER 2017-僅當該組中的所有數據都標記為已完成時,如何查詢以檢索該組數據?

[英]SQL SERVER 2017 - How do I query to retrieve a group of data only if all of the data inside that group are marked as completed?

我有一些如下的觀察表。 觀察數據可以是由觀察類別表確定的單獨形式或成組形式。

cat table (which holds category data)
id   | title    |    is_groupable
-------------------------------------------
1    | Cat 1    |    1
2    | Cat 2    |    1
3    | Cat 3    |    0
4    | Cat 4    |    0
5    | Cat 5    |    1

obs table (Holds observation data, groupable data are indicated by is_groupable of cat table, and the data is grouped in respect to index of obs table. and is_completed field indicates if some action has been taken on that or not)
id   | cat_id   |  index  | is_completed |  created_at
------------------------------------------------------
1    | 3        | 100     | 0            | 2017-12-01

2    | 4        | 400     | 1            | 2017-12-02
// complete action taken group indicated by 1 in is_completed field
3    | 1        | 200     | 1            | 2017-12-1
4    | 1        | 200     | 1            | 2017-12-1
// not complete action taken group
5    | 2        | 300     | 0            | 2017-12-1
6    | 2        | 300     | 1            | 2017-12-1
7    | 2        | 300     | 0            | 2017-12-1
// complete action taken group
8    | 5        | 400     | 1            | 2017-12-1
9    | 5        | 400     | 1            | 2017-12-1
10   | 5        | 400     | 1            | 2017-12-1

為了便於理解,我使用obs表中的以上注釋將已完成或未使用的數據集分開。

現在,我要實現的是從obs表中以組格式檢索數據集。 在上述情況下,組的集合是

{3,4} 
{5,6,7}
{8,9,10}

我想在結果中設置{3,4}和{8,9,10},因為該組中的每個數據都標記為is_completed:1我不需要{5,6,7}數據集,因為它只有6個標記為已完成,5個和7個未采取行動,因此未完成。

到目前為止,我所做的是(讓我們忽略單個案例,因為它非常簡單並且已經完成,對於分組案例,如果忽略所采取的措施,我也可以檢索分組數據,即我可以分組它們並檢索集合,無論是否采取了行動。)

(SELECT
null AS id,
cat.is_groupable AS is_grouped,
cat.title,
cat.id AS category_id,
o.index,
o.date,
null AS created_at,
null AS is_action_taken,

(
  --  individual observation
  SELECT
    oi.id AS "observation.id",
    oi.category_id AS "observation.category_id",
    oi.index AS "observation.index",
    oi.created_at AS "observation.created_at",

    -- action taken flag according to is_completed
    CAST(
      CASE 
          WHEN ((oi.is_completed) > 0) THEN 1
          ELSE 0
      END AS BIT
    ) AS "observation.is_action_taken",

    -- we might do some sort of comparison here
    CAST(
    (
       CASE
      --
      -- Check if total count == completed count
      WHEN (
          SELECT COUNT(obs.id)
           FROM obs
            WHERE obs.category_id = cat.id AND obs.index = o.index
      ) = (
          SELECT COUNT(obs.id)
          FROM obs
          WHERE obs.category_id = cat.id AND oi.index = o.index 
          AND oi.is_action_taken = 1
        ) then 1
      else 0
    end
  ) as bit
) as all_completed_in_group

  FROM observations oi  
  WHERE oi.category_id = cat.id
    AND oi.index = o.index
  FOR JSON PATH
) AS observations
FROM obs o
INNER JOIN cat ON cat.id = o.category_id
WHERE cat.is_groupable = 1
GROUP BY cat.id, cat.name, o.index, cat.is_groupable, o.created_at
)

讓我們不要繼續該查詢是否成功執行。 我只是想知道,是否有比該方法更好的方法,或者該方法是否正確。

希望這是您所需要的。 為了檢查組的完整性,我剛剛對具有is_completed = '0'的組使用了AND NOT EXISTS 內部聯接用於獲取相應的obs id。 該算法放在CTE(公用表表達式)中。 然后,我在CTE上使用STUFF來獲取輸出。

DECLARE @cat TABLE (id int, title varchar(100), is_groupable bit)
INSERT INTO @cat VALUES
 (1, 'Cat 1', 1), (2, 'Cat 2', 1), (3, 'Cat 3', 0), (4, 'Cat 4', 0), (5, 'Cat 5', 1)

DECLARE @obs TABLE (id int, cat_id int, [index] int, is_completed bit, created_at date)
INSERT INTO @obs VALUES
 (1, 3, 100, 0, '2017-12-01'), (2, 4, 400, 1, '2017-12-02')
-- complete action taken group indicated by 1 in is_completed field
,(3, 1, 200, 1, '2017-12-01'), (4, 1, 200, 1, '2017-12-01')
-- not complete action taken group
,(5, 2, 300, 0, '2017-12-01'), (6, 2, 300, 1, '2017-12-01'), (7, 2, 300, 0, '2017-12-01')
-- complete action taken group
,(8, 5, 400, 1, '2017-12-01'), (9, 5, 400, 1, '2017-12-01'), (10, 5, 400, 1, '2017-12-01')
;
WITH cte AS
(
SELECT C.id [cat_id]
      ,O2.id [obs_id]
  FROM @cat C INNER JOIN @obs O2 ON C.id = O2.cat_id
 WHERE C.is_groupable = 1 --is a group
   AND NOT EXISTS (SELECT *
                     FROM @obs O
                    WHERE O.cat_id = C.id
                      AND O.is_completed = '0'
                      --everything in the group is_completed
                  )
)
--Stuff will put everything on one row
SELECT DISTINCT 
          '{' 
        + STUFF((SELECT ',' + CAST(C2.obs_id as varchar)
                   FROM cte C2
                  WHERE C2.cat_id = C1.cat_id
                 FOR XML PATH('')),1,1,'')
        + '}' AS returnvals
  FROM cte C1

產生輸出:

returnvals
{3,4}
{8,9,10}

我會嘗試這種方法,訣竅是使用已完成的總和來對照該組的總存在量進行檢查。

;WITH aux AS (
SELECT o.cat_id, COUNT(o.id) Tot, SUM(CONVERT(int, o.is_completed)) Compl, MIN(CONVERT(int, c.is_groupable)) is_groupable
FROM obs o INNER JOIN cat c ON o.cat_id = c.id
GROUP BY o.cat_id
)
, res AS ( 
SELECT o.*, a.is_groupable
FROM obs o INNER JOIN aux a ON o.cat_id = a.cat_id
WHERE (a.Tot = a.Compl AND a.is_groupable = 1) OR a.Tot = 1
)
SELECT CONVERT(nvarchar(10), id) id, CONVERT(nvarchar(10), cat_id) cat_id
INTO #res
FROM res
SELECT * FROM #res
SELECT m.cat_id, LEFT(m.results,Len(m.results)-1) AS DataGroup
FROM
(
  SELECT DISTINCT r2.cat_id, 
  (
    SELECT r1.id + ',' AS [text()]
    FROM #res r1
    WHERE r1.cat_id = r2.cat_id
    ORDER BY r1.cat_id
    FOR XML PATH ('')
  ) results
  FROM #res r2
) m
ORDER BY DataGroup
DROP TABLE #res

轉換歸因於位數據類型

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM