我的SQL查询的哪一部分是错的?

时间:2014-09-29 13:30:57

标签: sql-server

部分SQL Server数据库实体是:

  • 表格(同上,柜台)
  • 群组(Id,Form_Id,Counter)
  • 字段(Id,Group_Id,Counter)

这种结构的逻辑是:

  • 字段计数器可以是0或更高
  • 组计数器取决于该组中存在的字段的计数器:每个字段的计数器值高于0会使组计数器增加一个
  • 组与表格之间存在相同的关系:表格计数器是组计数器的总和,大于0

最佳理解的一个小例子:

Form A1 (Counter: 1)
|-> Group BB1 (Counter: 2)
   |-> Field CCC1 (Counter: 2)
   |-> Field CCC2 (Counter: 1)
|-> Group BB2 (Counter: 0)
   |-> Field CCC3 (Counter: 0)
   |-> Field CCC4 (Counter: 0)
Form A2
...

某些字段包含我的查询需要检查的无效值。但我不能以正确的方式写出来。它的最后一个版本:

    select distinct
        cd.Id as [FormID],
        sum (case when cd.Counter > 0 then 1 else 0 end) over (partition by cd.Id, gd.Id, fd.Id) as [FormSum],
        cd.Counter as [FormVal],

        gd.Id as [GroupID],
        sum(case when gd.Counter > 0 then 1 else 0 end) over (partition by cd.Id, gd.Id, fd.Id) as [GroupSum],
        gd.Counter as [GroupVal],

        fd.Id as [FieldID],
        --sum(case when fd.Counter > 0 then 1 else 0 end) over (partition by cd.Id, gd.Id) as [FieldSum],
        fd.Counter as [FieldVal]
    from FieldDatas fd
    inner join GroupDatas gd on fd.GroupData_Id = gd.Id
    inner join CrfDatas cd on gd.CrfData_Id = cd.Id
    where cd.Id in
    (
        -- some subquery
    )
    order by cd.Id, gd.Id, fd.Id

更新
此查询需要将所有实体中保存的计数器数据与查询计算值进行比较,并在将来修复这些值。

对任何帮助都很乐意。

1 个答案:

答案 0 :(得分:1)

您无法使用单个查询更新两个表的内容,因此我们最终得到两个UPDATE语句。接下来,修复“较低”关系(组/字段)之前的“上部”关系。我采取的步骤:

首先设置测试结构和数据:

--  Set up test tables
CREATE TABLE Forms
(Id  int  not null
,Counter  int  not null)

CREATE TABLE Groups
(Id  int  not null
,Form_id  int  not null
,Counter  int not null)

CREATE TABLE Fields
(Id  int  not null
,Group_Id  int  not null
,Counter  int not null)


--  Set up valid test data
DELETE Forms DELETE Groups DELETE Fields
INSERT Forms values
  (1,1)
INSERT Groups values
  (1,1,2)
 ,(2,1,0)
INSERT Fields values
  (1,1,2)
 ,(2,1,1)
 ,(3,2,0)
 ,(4,2,0)


--  Set invalid Forms counter
DELETE Forms DELETE Groups DELETE Fields
INSERT Forms values
  (1,2)
INSERT Groups values
  (1,1,2)
 ,(2,1,0)
INSERT Fields values
  (1,1,2)
 ,(2,1,1)
 ,(3,2,0)
 ,(4,2,0)


--  Set invalid Groups counter (both) 
DELETE Forms DELETE Groups DELETE Fields
INSERT Forms values
  (1,2)
INSERT Groups values
  (1,1,0)
 ,(2,1,1)
INSERT Fields values
  (1,1,2)
 ,(2,1,1)
 ,(3,2,0)
 ,(4,2,0)


--  Mondo invalid
DELETE Forms DELETE Groups DELETE Fields
INSERT Forms values
  (1,0)
INSERT Groups values
  (1,1,0)
 ,(2,1,1)
INSERT Fields values
  (1,1,2)
 ,(2,1,1)
 ,(3,2,0)
 ,(4,2,0)

接下来,在“较低”集中识别错误数据:

--  Detect bad data in Groups/Fields relationship
SELECT
   gr.Id
  ,gr.Counter
  ,sum(case when fi.Counter <> 0 then 1 else 0 end) CalcValue
 from Groups gr
  left outer join Fields fi
   on fi.Group_Id = gr.Id
 group by
   gr.Id
  ,gr.Counter
 having sum(case when fi.Counter <> 0 then 1 else 0 end) <> gr.Counter

在更新语句中将其用作子查询:

--  Reset invalid Forms counters
UPDATE Groups
 set Counter = xx.CalcValue
 from Groups gr
  inner join (--  Detect bad data in Groups/Fields relationship
              select
                 gr.Id
                ,gr.Counter
                ,sum(case when fi.Counter <> 0 then 1 else 0 end) CalcValue
               from Groups gr
                left outer join Fields fi
                 on fi.Group_Id = gr.Id
               group by
                 gr.Id
                ,gr.Counter
               having sum(case when fi.Counter <> 0 then 1 else 0 end) <> gr.Counter) xx
   on xx.Id = gr.Id

剪切,粘贴,重命名为“上层”设置:

--  Detect bad data in Forms/Groups relationship
SELECT
   fo.Id
  ,fo.Counter
  ,sum(case when gr.Counter <> 0 then 1 else 0 end) CalcValue
 from Forms fo
  left outer join Groups gr
   on gr.Form_Id = fo.Id
 group by
   fo.Id
  ,fo.Counter
 having sum(case when gr.Counter <> 0 then 1 else 0 end) <> fo.Counter


--  Reset invalid Forms counters
UPDATE Forms
 set Counter = xx.CalcValue
 from Forms fo
  inner join (--  Detect bad data in Forms/Groups relationship
              select
                 fo.Id
                ,fo.Counter
                ,sum(case when gr.Counter <> 0 then 1 else 0 end) CalcValue
               from Forms fo
                left outer join Groups gr
                 on gr.Form_Id = fo.Id
               group by
                 fo.Id
                ,fo.Counter
               having sum(case when gr.Counter <> 0 then 1 else 0 end) <> fo.Counter) xx
   on xx.Id = fo.Id

按该顺序运行更新并查看结果:

SELECT * from Forms
SELECT * from Groups
SELECT * from Fields

假设:数据是干净的,如上所述,如果表格很大,则会正确设置索引,不会出现其他意料之外的差异。