【问题标题】:How to use IN in sql query when table has key , values pairs当表有键值对时如何在sql查询中使用IN
【发布时间】:2017-10-31 16:16:09
【问题描述】:

我正在处理具有键值对的查询

学生

StdId StuName   phnNum 
1     John       87678

student_meta_data

S.NO field_name   field_value     StdId  
1    college       St.Anns         1       
2    Address      Arizona          1       
3    IdNum         321             1       
4    Subject         Maths         1        
5    Marks          90             1
6   Subject        Physics         1
7   Marks          80              1

我想从 student_meta_data 表中获取数据,为此我编写了如下查询,

select 
   case when student_meta_data.field_name = 'Subject' Then field_value end as subject
   case when student_meta_data.field_name ='Marks' Then field_value end as marks
   case when student_meta_data.field_name = 'IdNum' Then field_value end as IdNum
 from student_meta_data

 where student_meta_data.StdId=1
       && student_meta_data.field_name in ('Subject')

对于上述查询,我​​正在获取如下记录,

subject   marks     IdNum
null      null      null

我希望获取如下记录,

subject   marks     IdNum    
Maths      90        321       
Physics    80        321       

你能在这方面提出建议吗?提前致谢。

【问题讨论】:

  • MAX(case...end) subject... GROUP BY something - 并且(显然?)最后失去了主题条件。
  • @Strawberry 我也尝试使用 MAX(case ...) 函数。但它不起作用
  • 我认为你应该从 where 子句中删除第二个条件
  • @Harshil 我也尝试删除它,但没有运气

标签: mysql database


【解决方案1】:

SQL DEMO

SELECT rn, 
       MAX(subject) as subject, 
       MAX(case when field_name = 'Marks' Then field_value end) as marks,
       MAX(idNum) as idNum

FROM ( SELECT m.*,
              @idNum := if(`field_name` = 'IdNum', `field_value`, @idNum) as idNum,
              @subject := if(`field_name` = 'Subject', `field_value`, @subject) as subject,
              @rn := if (@s = @subject, 
                         @rn,
                         if(@s := @subject, @rn+1, @rn+1)
                        ) as rn
       FROM student_meta_data m
       CROSS JOIN (SELECT @idNum := 0, @rn := 0, @subject := '', @s := '' ) as var
       ORDER BY `SNO` ) as T
WHERE rn > 0       
GROUP BY rn;  

输出

使用变量跟踪 idNum 并为每个主题创建组。第一个查询只是调试建议的内部子查询,最后是您想要的结果

【讨论】:

  • 您不需要分组,因为您已经按StdId=1 过滤,所以MAX() 将返回该组的最大值。
  • 主题标记 IdNum null null null
  • 检查这个rextester.com/NCH6542 ...不是正确的答案,但不应该返回空值。我看到的问题是无法分辨哪个标记对应哪个主题
  • 嗯,或许有办法。
  • @Strawberry 你可以使用S.NO 命令,但IdNum 只会出现一次
【解决方案2】:

您的数据模型还有很多不足之处。不过,这里有一些需要考虑的事情......

SELECT a.field_value subject
     , b.field_value marks 
  FROM 
     ( SELECT x.*
            , MIN(y.id) y_id 
         FROM student_meta_data x 
         JOIN student_meta_data y 
           ON y.id > x.id 
          AND y.field_name = 'marks' 
        WHERE x.field_name = 'subject' 
        GROUP 
           BY x.id
     ) a 
  JOIN student_meta_data b 
    ON b.id = a.y_id;
+---------+-------+
| subject | marks |
+---------+-------+
| Maths   | 90    |
| Physics | 80    |
+---------+-------+

【讨论】:

  • 您缺少 IdNum 列
  • @GurwinderSingh 我没有遗漏任何东西
  • OP 的期望结果有 IdNum。您的查询没有。
  • @GurwinderSingh 也许您没有完整阅读我的答案。
  • 我明白了.. 但是你可以说,而不是他没有阅读答案:(
【解决方案3】:

我怎么强调都不为过,但是您的设计需要改变。规范化它。


源自@Juan 的回答。

您可以使用用户变量和简单的过滤来做到这一点。

select idnum, subject, marks
from (
    select 
        @idnum   := if(field_name='IdNum', field_value, @idnum) as idnum,
        @subject := if(field_name='Subject', field_value, @subject) as subject,
        @marks   := if(field_name='Marks', field_value, @marks) as marks,
        m.field_name
    from student_meta_data
    cross join (
        select  @idnum   := 0, 
                @subject := null,
                @marks   := 0
        ) x
    order by sno
    ) t
where field_name = 'Marks';

我仅基于 Marks field_name 进行过滤,因为它在给定顺序中排在最后,届时我们将设置所有其他必需的值。

Demo

【讨论】:

    猜你喜欢
    • 2016-01-05
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 2021-06-17
    • 1970-01-01
    • 2019-12-31
    • 1970-01-01
    • 2021-09-04
    相关资源
    最近更新 更多