在我自己的列中使用 SQL 中的算术来填充第三列,其中它为零。 (复杂,仅当满足某些条件时)

Using Arithmetic in SQL on my own columns to fill a third column where it is zero. (complicated, only when certain criteria is met)

所以这是我的问题。振作起来,因为你需要一些思考才能让你的头脑围绕我正在尝试做的事情。 我正在与 Quarterly census employment and wage data 合作。 QCEW 数据有一种称为抑制代码的东西。如果数据面额(总体、位置商以及每年每个季度的年度数据)被抑制,则该面额的所有数据均为零。我的 table 设置如下(只显示与问题相关的列):

A County_Id column,              
Industry_ID column,  
Year column,  
Qtr column,

隐藏列(0 表示未隐藏,1 表示隐藏),
Data_Category 列(1 表示总体,2 表示 lq,3 表示全年),
Data_Denomination 列(1-8 表示在该类别中查看的具体数据,例如:每月就业、应税工资等典型数据), 和一个值列(如果 Data_Category 被抑制,它将为零 - 因为所有数据面额值都将为零)。

现在,如果 1991 年第 1 季度的总体数据(类别 1)被抑制,但明年第 1 季度的总体数据和全年(类别 1 和 3)都没有被抑制,那么我们可以推断自 OTY1991q1 = (Overall1991q1 - Overall1990q1) 以来,第一年的抑制数据的价值是多少。因此,为了找到被抑制的数据,我们只需从 cat 3(denom 1-8)值中减去 cat 1(denom 1-8)值,以替换前一年抑制值中的零。这在数学上很容易掌握,困难在于有数百万列可以用来检查这些标准。我正在尝试编写某种 SQL 查询来为我执行此操作,检查以确保 Overall-n qtr-n 被抑制,然后查看下一年是否对整体和oty,(可能是某种复杂的案例陈述?然后,如果满足这些条件,则对两个 Data_Cat-Data_Denom 类别执行算术运算,并替换相应的 Cat-Denom 值中的零。

下面是一个简单示例(已删除不相关 data_cats),我希望它能帮助理解我正在尝试做的事情。

|CountyID IndustryID Year Qtr Suppressed Data_Cat Data_Denom Value                                                                          
| 5            10      1990  1      1          1        1        0                                                                                                                                                     
| 5            10      1990  1      1          1        2        0                                                                                                                                                     
| 5            10      1990  1      1          1        3        0                                                                                                                                                     
| 5            10      1991  1      0          1        1        5                                                                                                                                                     
| 5            10      1991  1      0          1        2        15                                                                                                                                                    
| 5            10      1991  1      0          1        3        25                                                                                                                                                    
| 5            10      1991  1      0          3        1        20                                                                                                                                                    
| 5            10      1991  1      0          3        2        20                                                                                                                                                    
| 5            10      1991  1      0          3        3        35  

所以基本上我们在这里要做的是从每个数据类别中获取整体数据(我删除了 lq ~ data_cat 2)因为它不相关并且 data_denom(哪个为简单起见,我已将 1991 年的 8 缩小到 3),从 1991 年的总值中减去它,就会得到适用的
|上一年 1990 年的价值 cat_1。所以这里 data_cat 1 Data_denom 1 将是 15 (20-5),denom 2 将是 5(20-15),denom 3 将是 10(35-25)。 (Oty 1991q1 - 整体 1991q1) = 1990q1。我希望这有帮助。就像我说的那样,问题不在于数学,它正在制定一个将检查此条件数百万次的查询。

如果你想在下一年和一个季度找到具有 2 行未压缩数据的压缩数据,我们可以使用 cross apply() 来做这样的事情:

测试设置:http://rextester.com/ORNCFR23551

使用 cross apply() 到 return 具有有效派生值的行:

select t.*
  , NewValue = cat3.value - cat1.value
from t
  cross apply (
      select i.value 
      from t as i
      where i.CountyID   = t.CountyID
        and i.IndustryID = t.IndustryID
        and i.Data_Denom = t.Data_Denom 
        and i.Year       = t.Year +1
        and i.Qtr        = t.Qtr
        and i.Suppressed = 0
        and i.Data_Cat   = 1
  ) cat1
  cross apply (
      select i.value 
      from t as i
      where i.CountyID   = t.CountyID
        and i.IndustryID = t.IndustryID
        and i.Data_Denom = t.Data_Denom 
        and i.Year       = t.Year +1
        and i.Qtr        = t.Qtr 
        and i.Suppressed = 0
        and i.Data_Cat   = 3
  ) cat3
where t.Suppressed = 1
  and t.Data_Cat   = 1

return秒:

+----------+------------+------+-----+------------+----------+------------+-------+----------+
| CountyID | IndustryID | Year | Qtr | Suppressed | Data_Cat | Data_Denom | Value | NewValue |
+----------+------------+------+-----+------------+----------+------------+-------+----------+
|        5 |         10 | 1990 |   1 |          1 |        1 |          1 |     0 |       15 |
|        5 |         10 | 1990 |   1 |          1 |        1 |          2 |     0 |        5 |
|        5 |         10 | 1990 |   1 |          1 |        1 |          3 |     0 |       10 |
+----------+------------+------+-----+------------+----------+------------+-------+----------+


使用 outer apply() 到 return 所有行

select t.*
  , NewValue = coalesce(nullif(t.value,0),cat3.value - cat1.value,0)
from t
  outer apply (
      select i.value 
      from t as i
      where i.CountyID   = t.CountyID
        and i.IndustryID = t.IndustryID
        and i.Data_Denom = t.Data_Denom 
        and i.Year       = t.Year +1
        and i.Qtr        = t.Qtr
        and i.Suppressed = 0
        and i.Data_Cat   = 1
  ) cat1
  outer apply (
      select i.value 
      from t as i
      where i.CountyID   = t.CountyID
        and i.IndustryID = t.IndustryID
        and i.Data_Denom = t.Data_Denom 
        and i.Year       = t.Year +1
        and i.Qtr        = t.Qtr
        and i.Suppressed = 0
        and i.Data_Cat   = 3
  ) cat3

returns:

+----------+------------+------+-----+------------+----------+------------+-------+----------+
| CountyID | IndustryID | Year | Qtr | Suppressed | Data_Cat | Data_Denom | Value | NewValue |
+----------+------------+------+-----+------------+----------+------------+-------+----------+
|        5 |         10 | 1990 |   1 |          1 |        1 |          1 |     0 |       15 |
|        5 |         10 | 1990 |   1 |          1 |        1 |          2 |     0 |        5 |
|        5 |         10 | 1990 |   1 |          1 |        1 |          3 |     0 |       10 |
|        5 |         10 | 1991 |   1 |          0 |        1 |          1 |     5 |        5 |
|        5 |         10 | 1991 |   1 |          0 |        1 |          2 |    15 |       15 |
|        5 |         10 | 1991 |   1 |          0 |        1 |          3 |    25 |       25 |
|        5 |         10 | 1991 |   1 |          0 |        3 |          1 |    20 |       20 |
|        5 |         10 | 1991 |   1 |          0 |        3 |          2 |    20 |       20 |
|        5 |         10 | 1991 |   1 |          0 |        3 |          3 |    35 |       35 |
+----------+------------+------+-----+------------+----------+------------+-------+----------+

更新 1 - 修复了一些列名称

更新 2 - 改进了第二个查询中的别名


好的,我想我明白了。

如果您只是想做出这样的推断,那么以下内容可能会有所帮助。 (如果这只是您想在填补数据空白时做出的众多推论中的第一个,您可能会发现不同的方法会导致更有效的解决方案来执行 both/all 个推论,但我想当您跨过那座桥时到达那里...)

虽然大部分基本逻辑保持不变,但您如何调整它取决于您是否希望查询 只是 提供您将推断的值(例如驱动UPDATE 语句),或者是否要在更大的查询中使用此逻辑内联。出于性能原因,我怀疑前者更有意义(尤其是如果您可以执行一次更新,然后多次读取生成的数据集),所以我将从以这种方式构建事物开始,稍后再回到另一个。 ..

听起来您有一个包含所有这些列的 table(我将其称为 QCEW)。在这种情况下,使用连接将每个抑制的整体数据点(以下代码中的 c_oa)与一年后相应的整体和 oty 数据点相关联:

SELECT c_oa.*, n_oa.value - n_oty.value inferred_value
  FROM           QCEW c_oa    --current yr/qtr overall
      inner join QCEW n_oa    --next yr (same qtr) overall
              on c_oa.countyId = n_oa.countyId
             and c_oa.industryId = n_oa.industryId
             and c_oa.year = n_oa.year - 1
             and c_oa.qtr = n_oa.qtr
             and c_oa.data_denom = n_oa.data_denom
      inner join QCEW n_oty   --next yr (same qtr) over-the-year
              on c_oa.countyId = n_oty.countyId
             and c_oa.industryId = n_oty.industryId
             and c_oa.year = n_oty.year - 1
             and c_oa.qtr = n_oty.qtr
             and c_oa.data_denom = n_oty.data_denom
 WHERE c_oa.SUPPRESSED = 1
   AND c_oa.DATA_CAT = 1
   AND n_oa.SUPPRESSED = 0
   AND n_oa.DATA_CAT = 1
   AND n_oty.SUPPRESSED = 0
   AND n_oty.DATA_CAT = 3

现在听起来 table 很大,我们刚刚加入了它的 3 个实例;因此,要使其正常工作,您需要良好的物理设计(适当的 indexes/stats 用于连接列等)。这就是为什么我建议基于上述查询进行一次更新;当然,它可能 运行 很长,但是您可以立即阅读推断值。

但如果您真的想将其直接合并到数据查询中,您可以对其进行一些修改以显示 所有 值,并混合推断值。我们需要切换到外部连接来做到这一点,我将用连接条件做一些稍微奇怪的事情来使它适合:

SELECT src.COUNTYID
     , src.INDUSTRYID
     , src.YEAR
     , src.QTR
     , case when (n_oa.value - n_oty.value) is null 
            then src.suppressed 
            else 2
       end as SUPPRESSED_CODE -- 0=NOT SUPPRESSED, 1=SUPPRESSED, 2=INFERRED
     , src.DATA_CAT
     , src.DATA_DENOM
     , coalesce(n_oa.value - n_oty.value, src.value) as VALUE
  FROM          QCEW src     --a source row from which we'll generate a record
      left join QCEW n_oa    --next yr (same qtr) overall (if src is suppressed/overall)
             on src.countyId = n_oa.countyId
            and src.industryId = n_oa.industryId
            and src.year = n_oa.year - 1
            and src.qtr = n_oa.qtr
            and src.data_denom = n_oa.data_denom
            and src.SUPPRESSED = 1 and n_oa.SUPPRESSED = 0
            and src.DATA_CAT = 1 and n_oa.DATA_CAT = 1
      left join QCEW n_oty   --next yr (same qtr) over-the-year (if src is suppressed/overall)
             on src.countyId = n_oty.countyId
            and src.industryId = n_oty.industryId
            and src.year = n_oty.year - 1
            and src.qtr = n_oty.qtr
            and src.data_denom = n_oty.data_denom
            and src.SUPPRESSED = 1 and n_oty.SUPPRESSED = 0
            and src.DATA_CAT = 1 and n_oty.DATA_CAT = 3