【问题标题】:SQL Query for this requirement此要求的 SQL 查询
【发布时间】:2013-05-29 07:14:54
【问题描述】:

我有一个带有表 samplesurveytypestatus 的 sqlite 数据库。所有 3 个表的主键 id 都设置为表“操作”的外键。请参见下图中的场景

我的operation 表因此具有值

采样为

和状态

调查类型为

必填

我需要实现的是

从操作表中获取status id信息,并针对所有调查类型的特定建筑物显示。

试过

我找到了一种方法,通过程序循环获取所有样本 ID 和所有调查类型 ID,并获取单个状态 ID 作为

for all sampleid in sample table
{
   for all statustypeid in statustype table
   {  
      select statusid from operation where sampleid = 2 and surveytypeid=1
    }
}

sql单查询有没有更好的选择来生成包含所有值的表

注意:使用 sqlite,适用于 ios 应用程序

【问题讨论】:

  • 很好的表示+1。你用什么软件来显示 sql 架构?
  • 架构图:Valentina studio,数据表示:Sqlitemanager,在 mac OS X 上工作

标签: mysql ios sql sqlite


【解决方案1】:

首先:为什么 Operation.StatusID 是 Text 类型的,当它填充来自整数字段的值时? 可能会询问有关 RegionID 的相同问题,但由于此处未列出 Region 表,我无法确定,也许您在特定情况下需要 Text。但是将 Operation.StatusID 作为 Text 是完全不合理的,并且会给您带来性能损失。

尽管如此,有一个古老的技巧,称为旋转,但它仅适用于固定数量的列,在您的情况下 - 调查:

SELECT
  Sample.BuildingID,
  MAX(Sample.BuildingName_EN) BuildingID,
  MAX(CASE WHEN Operation.SurveyTypeID=1 THEN Operation.StatusID ELSE " " END) AS Survey1,
  MAX(CASE WHEN Operation.SurveyTypeID=2 THEN Operation.StatusID ELSE " " END) AS Survey2,
  MAX(CASE WHEN Operation.SurveyTypeID=3 THEN Operation.StatusID ELSE " " END) AS Survey3
FROM Sample,Operation
WHERE Operation.SampleID=Sample.ID
GROUP BY Sample.BuildingID

更新: 为确保此解决方案的可扩展性,您必须在每次与另一个查询一起使用之前生成此查询:

SELECT '  SELECT Sample.BuildingID,MAX(Sample.BuildingName_EN) BuildingID,'
UNION ALL
SELECT concat(' MAX(CASE WHEN Operation.SurveyTypeID=',SurveyType.ID,' THEN Operation.StatusID ELSE " " END) AS "',SurveyType.LongName,'",') from SurveyType
UNION ALL
SELECT '0 as dummy FROM Sample,Operation WHERE Operation.SampleID=Sample.ID GROUP BY Sample.BuildingID'

或者,对于 Oracle 和 SQLite:

SELECT '  SELECT Sample.BuildingID,MAX(Sample.BuildingName_EN) BuildingID,'
UNION ALL
SELECT ' MAX(CASE WHEN Operation.SurveyTypeID='||SurveyType.I||' THEN Operation.StatusID ELSE " " END) AS "'||SurveyType.LongName||'",' from SurveyType
UNION ALL
SELECT '0 as dummy FROM Sample,Operation WHERE Operation.SampleID=Sample.ID GROUP BY Sample.BuildingID'

【讨论】:

  • 你说得对。会处理它。但是如果我在调查类型列中再插入一个值呢?
  • 好吧,不幸的是,在纯 SQL 中没有非编程方式可以做到这一点。我将使用解决方法更新答案。
  • 生成字符串中的尾随空格确保UNION ALL结果的升序
  • 错误:没有这样的功能:concat
  • 对不起,你发在MYSQL部分,所以我使用了MYSQL字符串连接功能。使用 ||运算符。
【解决方案2】:

您希望每种调查类型都有一列。 这是无法直接实现的,因为 SQLite 没有数据透视函数。

您需要执行两个步骤。 首先,获取所有调查类型:

SELECT ID, Longname FROM SurveyType

然后,使用这些值构造一个查询,其中每个调查类型列都有一个子查询,如下所示:

SELECT BuildingName_EN AS 'Building Name',
       BuildingID AS 'Building id',
       (SELECT StatusID FROM Operation
        WHERE SampleID = Sample.ID AND SurveyTypeID = 1) AS 'Survey 1',
       (SELECT StatusID FROM Operation
        WHERE SampleID = Sample.ID AND SurveyTypeID = 2) AS 'Survey 2',
       (SELECT StatusID FROM Operation
        WHERE SampleID = Sample.ID AND SurveyTypeID = 3) AS 'New Survey 3'
FROM Sample

【讨论】:

  • 谢谢。但是如果我在调查类型中有更多值?有什么方法可以以通用方式操纵列的名称吗?
  • 这就是数据透视函数的用途,如果数据库有的话。
  • 所以在 sqlite 中这是唯一的选择?
  • 是的,您必须动态创建查询。
【解决方案3】:

我不会讨论模型本身,但存在一对多的关系Sample[1]-[*]Operation。 因此,如果您想在 SQL 行中查询样本的所有操作,您必须编写子选择。 这只有在可能的操作数量固定并且我假设它是动态的情况下才能完成。

更常见的方法是对重复的样本条目进行 qyery 关系并在代码中处理它

SELECT s.building_name, s.building_id, o.statusID 
from sample s, operation o
where s.id = o.sampleid

另一种方法是在单独的查询中为给定状态选择操作。

SELECT o.statusID 
operation o
where o.sampleid  = 12 

【讨论】:

    【解决方案4】:

    您需要对数据进行透视,不幸的是,在 mysql 中您无法动态实现这一点。

    试试这个:

    SELECT
        s.BuildingName_EN as building_name,
        s.ID building_id,
        SUM(CASE WHEN st.LongName = 'Survey1' THEN sa.ID ELSE 0 END) as Survey1,
        SUM(CASE WHEN st.LongName = 'Survey2' THEN sa.ID ELSE 0 END) as Survey2,
        SUM(CASE WHEN st.LongName = 'New Survey 3' THEN sa.ID ELSE 0 END) as 'New Survey 3'
    FROM 
        Operation o
    LEFT JOIN Sample s
        ON o.SampleID = s.ID 
    LEFT JOIN Status sa
        ON o.StatusID = sa.ID 
    LEFT JOIN SurveyType st
        ON o.SurveyTypeID = st.ID 
    GROUP BY
        s.ID
    

    【讨论】:

    • 请注意我正在使用 sqlite
    • 在 sqlite 中也应该没问题。 “SQLite 理解大多数标准 SQL 语言。” SUM,IF,JOINGROUP BY 都存在于 sqlite 中
    • 哈哈,它有IFNULL 但没有IF...我已经使用CASE 更新了查询,请立即尝试
    【解决方案5】:
    For this first you have to join two tables like : Operation and Sample with SurveyType and then pivot the column 'LongName' of SurveyType. We can achieve it dynamically. 
    
    Here is the query...
    
    
    
    Select * FROM 
    (Select Sample.BuildingName_EN AS 'Building Name', 
            Sample.BuildingID,
            SurveyType.LongName,
            Operation.StatusID 
    from SurveyType
    Inner Join Operation ON 
        Operation.SurveyTypeID = SurveyType.ID
    Inner Join Sample ON
        Operation.SampleID = Sample.ID
        ) P
    PIVOT
    (
    MAX(StatusID)
    FOR LongName
    IN ([Survey 1],[Survey 2],[New Survey 3])
    ) AS pvt
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-02
      • 1970-01-01
      • 1970-01-01
      • 2017-04-19
      • 1970-01-01
      • 2011-02-22
      • 1970-01-01
      相关资源
      最近更新 更多