使用可能的UNION的SQL一对多

时间:2016-09-15 20:21:56

标签: php sql angularjs json

我对我正在构建的查询有疑问,我想在SQL语句中完成所有操作。

所以,我有一个这样的数据表:

+-----+-----+-----+-----+
| pid | did | src | val |
+-----+-----+-----+-----+
|   1 |   1 | lab |   0 |
|   1 |   1 | lab |   1 |
|   2 |   3 | pl  |   1 |
|   1 |   1 | pl  |   1 |
|   2 |   1 | med |   1 |
|   1 |   1 | med |   1 |
+-----+-----+-----+-----+

有一个ID列(pid)和一个疾病列(did),一个source(src)列和一个value(val)列。疾病专栏还有我创建的标准化表格:

+-----+-----------------+
| did |      name       |
+-----+-----------------+
|   1 | Lung Cancer     |
|   2 | Alcoholism      |
|   3 | Obesity         |
|   4 | Diabetes        |
|   5 | Viral Infection |
+-----+-----------------+ 

这里的真正诀窍是我需要进行一个查询,该查询会生成一个表,该表生成一个显示每个pid(ID)的新表,以及该疾病的相关文本名(did),这可能是一个JOIN使用规范化表格。

棘手的部分是,对于每个ID,我需要计算(3)个可能来源(src)的EACH的出现次数,因此可能会有5-10个ID出现,并且每个出现1个这些将有一个src关联:MED,LAB或PL。我需要按照记录计算这些数据并显示在下面的表格中。

+-----+------------------------+--------------------------+----------------------+
| pid |      Lung Cancer       |        Alcoholism        |       Obesity              
+-----+------------------------+--------------------------+----------------------+
|   1 | Yes                    | Maybe                    | No                   |
|     | (med: 2, lab: 1, pl:1) | (med: 0, lab: 1, pl:1)   | (med:0, lab:0, pl:0) |
+-----+------------------------+--------------------------+----------------------+

因此可能有5-10行,ID为1,并且对于每一行,将分配一个src(source),它将是三个值之一(lab,pl,med),这些将具有值0 0或1。

最后会有一个计数,基本上有三个状态到达(是)他们有疾病,(每个来源的所有1或以上),或两个零,但是一个人有一个或多个(可能),或全部为零,(不)

我不确定所有这些都可以用SQL语句完成......或者我可以使用JOIN / UNION或某种组合来构建一个新表并放置所有值,然后json_encode它(我' m使用PHP),然后使用Angular对src值进行排序并进行计算并显示"是"," No"的引导按钮。或"可能"

谢谢你们的帮助!这是一个令人费解的SQL语句,或者至少我是这么认为的。

3 个答案:

答案 0 :(得分:1)

这很简单,只需按步骤进行..首先卷起src:

SELECT pid, did, 
       sum(CASE WHEN src='med' THEN val ELSE O END) AS med,
       sum(CASE WHEN src='lab' THEN val ELSE O END) AS lab,
       sum(CASE WHEN src='pl' THEN val ELSE O END) AS pl
FROM table_of_data
GROUP BY pid, did

现在按照

进入列
SELECT pid,
       max(CASE WHEN did=1 THEN '(med:'|| CAST(med as varchar(5)) ||
                            ', lab:'|| CASE(lab as varchar(5)) ||
                            ', pl:' || CAST(pl as varhcar(5)) || ')' 
                       ELSE null END) AS Lung_Cancer,  
       max(CASE WHEN did=2 THEN '(med:'|| CAST(med as varchar(5)) ||
                            ', lab:'|| CASE(lab as varchar(5)) ||
                            ', pl:' || CAST(pl as varhcar(5)) || ')' 
                       ELSE null END) AS Alcoholism,  
       max(CASE WHEN did=3 THEN '(med:'|| CAST(med as varchar(5)) ||
                            ', lab:'|| CASE(lab as varchar(5)) ||
                            ', pl:' || CAST(pl as varhcar(5)) || ')' 
                       ELSE null END) AS Obesity,  
       max(CASE WHEN did=4 THEN '(med:'|| CAST(med as varchar(5)) ||
                            ', lab:'|| CASE(lab as varchar(5)) ||
                            ', pl:' || CAST(pl as varhcar(5)) || ')' 
                       ELSE null END) AS Diabetes,  
       max(CASE WHEN did=5 THEN '(med:'|| CAST(med as varchar(5)) ||
                            ', lab:'|| CASE(lab as varchar(5)) ||
                            ', pl:' || CAST(pl as varhcar(5)) || ')' 
                       ELSE null END) AS Viral_Infection,  
FROM prior_result
GROUP BY pid

要得到是否可以使用先前结果中的案例

SELECT pid, did,
       CASE WHEN med+lab+pl > 3 THEN 'Yes'
            WHEN med+lab+pl = 0 THEN 'No'
            ELSE 'Maybe' END AND as have_it
FROM prior_result

没问题......把它们放在一起就可以了

SELECT pid,
       max(CASE WHEN did=1 THEN '(med:'|| CAST(med as varchar(5)) ||
                            ', lab:'|| CASE(lab as varchar(5)) ||
                            ', pl:' || CAST(pl as varhcar(5)) || ')' 
                       ELSE null END) AS Lung_Cancer,  
       max(CASE WHEN did=1 THEN
                             CASE WHEN med+lab+pl > 3 THEN 'Yes'
                                  WHEN med+lab+pl = 0 THEN 'No'
                                  ELSE 'Maybe'
                              END
                            ELSE null END) AS Have_Lung_Cancer,  

       max(CASE WHEN did=2 THEN '(med:'|| CAST(med as varchar(5)) ||
                            ', lab:'|| CASE(lab as varchar(5)) ||
                            ', pl:' || CAST(pl as varhcar(5)) || ')' 
                       ELSE null END) AS Alcoholism,  
       max(CASE WHEN did=2 THEN
                             CASE WHEN med+lab+pl > 3 THEN 'Yes'
                                  WHEN med+lab+pl = 0 THEN 'No'
                                  ELSE 'Maybe'
                              END
                            ELSE null END) AS Have_Alcoholism,  

       max(CASE WHEN did=3 THEN '(med:'|| CAST(med as varchar(5)) ||
                            ', lab:'|| CASE(lab as varchar(5)) ||
                            ', pl:' || CAST(pl as varhcar(5)) || ')' 
                       ELSE null END) AS Obesity,  
       max(CASE WHEN did=3 THEN
                             CASE WHEN med+lab+pl > 3 THEN 'Yes'
                                  WHEN med+lab+pl = 0 THEN 'No'
                                  ELSE 'Maybe'
                              END
                            ELSE null END) AS Have_Obesity,  

       max(CASE WHEN did=4 THEN '(med:'|| CAST(med as varchar(5)) ||
                            ', lab:'|| CASE(lab as varchar(5)) ||
                            ', pl:' || CAST(pl as varhcar(5)) || ')' 
                       ELSE null END) AS Diabetes,  
       max(CASE WHEN did=4 THEN
                             CASE WHEN med+lab+pl > 3 THEN 'Yes'
                                  WHEN med+lab+pl = 0 THEN 'No'
                                  ELSE 'Maybe'
                              END
                            ELSE null END) AS Have_Diabetes,  

       max(CASE WHEN did=5 THEN '(med:'|| CAST(med as varchar(5)) ||
                            ', lab:'|| CASE(lab as varchar(5)) ||
                            ', pl:' || CAST(pl as varhcar(5)) || ')' 
                       ELSE null END) AS Viral_Infection,  
       max(CASE WHEN did=5 THEN
                             CASE WHEN med+lab+pl > 3 THEN 'Yes'
                                  WHEN med+lab+pl = 0 THEN 'No'
                                  ELSE 'Maybe'
                              END
                            ELSE null END) AS Have_Viral_Infection,  

FROM (
  SELECT pid, did, 
       sum(CASE WHEN src='med' THEN val ELSE O END) AS med,
       sum(CASE WHEN src='lab' THEN val ELSE O END) AS lab,
       sum(CASE WHEN src='pl' THEN val ELSE O END) AS pl
  FROM table_of_data
  GROUP BY pid, did
) sub
GROUP BY pid

答案 1 :(得分:0)

看到你可能需要在某些时候动态地计算出所有这些,这是一种获得结果的方法,然后以比@hogan的答案少一点的方式转动,但这是基于他的答案。

SELECT
    d.pid
    ,COALESCE(MAX(CASE WHEN d.did = 1 THEN colString END),'No (med:0 lab:0 pl:0)') as Lung_Cancer
    ,COALESCE(MAX(CASE WHEN d.did = 2 THEN colString END),'No (med:0 lab:0 pl:0)') as Alcoholism
    ,COALESCE(MAX(CASE WHEN d.did = 3 THEN colString END),'No (med:0 lab:0 pl:0)') as Obesity
FROM
    (
     SELECT pid, did, 
          CONCAT(CASE
             WHEN SUM(Val) > 2 THEN 'Yes'
             WHEN SUM(Val) > 1 THEN 'Maybe'
             ELSE 'No'
          End
          ,' (med:'
          ,CAST(SUM(CASE WHEN src='med' THEN val ELSE 0 END) AS CHAR(5))
          ,' lab:'
          ,CAST(SUM(CASE WHEN src='lab' THEN val ELSE 0 END) AS CHAR(5))
          ,' pl:'
          ,CAST(SUM(CASE WHEN src='pl' THEN val ELSE 0 END) AS CHAR(5))
          ,')') as colString

     FROM TableP
     GROUP BY pid, did
    ) d
GROUP BY
    d.pid

请注意,当特定疾病的PID没有值时,使用COALESCE会处理。 sql小提琴:http://www.sqlfiddle.com/#!9/44ac9/11

只是为了向您展示它可以在没有子查询的情况下完成:

SELECT
    pid
    ,CONCAT(CASE
       WHEN SUM(CASE WHEN did = 1 THEN val ELSE 0 END) > 2 THEN 'Yes'
       WHEN SUM(CASE WHEN did = 1 THEN val ELSE 0 END) > 1 THEN 'Maybe'
       ELSE 'No'
    END
    , ' (med:'
    ,CAST(SUM(CASE WHEN did = 1 and src = 'med' THEN val ELSE 0 END) AS CHAR(5))
    , ', lab:'
    ,CAST(SUM(CASE WHEN did = 1 and src = 'lab' THEN val ELSE 0 END) AS CHAR(5))
    , ', pl:'
    ,CAST(SUM(CASE WHEN did = 1 and src = 'pl' THEN val ELSE 0 END) AS CHAR(5))
    ,')' ) AS Lung_Cancer

    .......repeat per disease

FROM
    table_of_data
GROUP BY
    pid

这种技术的SQL小提琴http://www.sqlfiddle.com/#!9/44ac9/13

答案 2 :(得分:0)

由于你也有一定数量的有效来源,你也应该有一张桌子:

+-----+-----+
| src | pos |
+-----+-----+
| lab | 2   |
| med | 1   |
| pl  | 3   |
+-----+-----+

(列pos表示您希望显示源的结果中的哪个位置。)

然后交叉加入疾病和来源以获得所有组合。外部连接数据表以获得所需的pid和每个desease和source的计数。其余的主要是字符串连接:

set @pid = 1;

select
  pid, 
  name, 
  concat
  (
    case when count(sumval) <> count(*) then 'Maybe'
         when min(sumval) > 0 then 'Yes' 
         when max(sumval) = 0 then 'No'
         else 'Maybe'
    end,
    ' (',
    group_concat(concat(src, ': ', coalesce(sumval, '?')) order by pos separator ', '),
    ')'
  ) as result
from
(
  select @pid as pid, d.*, s.*, sum(data.val) as sumval 
  from desease d
  cross join source s
  left join data on  data.did = d.did
                 and data.src = s.src 
                 and data.pid = @pid
  group by d.did, s.src
) sumvals
group by did
having count(sumval) > 0;

这为您提供了如下行:

+-----+-----------------+-------------------------------+
| pid | name            | result                        |
+-----+-----------------+-------------------------------+
| 1   | Lung Cancer     | Yes (med: 2, lab: 1, pl: 1)   |
| 1   | Alcoholism      | Maybe (med: 0, lab: 1, pl: 1) |
| 1   | Obesity         | No (med: 0, lab: 0, pl: 0)    |
+-----+-----------------+-------------------------------+

如果没有pid,desease和source的条目,我们不知道desease是否适用。在这种情况下,sumval为空。如果一个desease甚至没有一个条目,那么我们根本就不显示它(参见having子句)。否则,如果至少有一个来源和另一个缺失,我们会得出'Maybe'。

这是SQL小提琴:http://sqlfiddle.com/#!9/c2ac29/1

GUI层的任务是关心布局(在您的情况下:以列显示结果)。