【问题标题】:Building complex SQL query when one value depend on other value in query当一个值依赖于查询中的另一个值时构建复杂的 SQL 查询
【发布时间】:2015-07-13 01:32:44
【问题描述】:

数据库:

Table_Sensor:
    sensor_id,
    sensor_name

Table_Sensor_Detection:
    sensor_id
    azimuth (azimuth from specific sensor)

用户可以输入多个Sensor,所以我定义了Set < Integer> sensorsSet

用户也可以输入azimuth for each sensor,所以我为每个传感器输入Sensor.azimuth

我需要的只是 SQL 语句的逻辑,它将为输入的 sensors_ids 提供所有 sensor_detections,并为每个传感器提供足够方位角的另一个查询。

这是List< String> queryList,描述了我想要完成的逻辑。

for(Integer enteredSensorId:sensorsSet)
{
    querysList.add(
        "SELECT s FROM Table_Sensor_Detection s " +
        "WHERE s.sensor_id="+enteredSensorId +
        "AND s.azimuth"=getAzimuthForSenzor(enteredSensorId)
    );
}

上面的代码是简化的,所以不要为可能的错误而烦恼。我只想找出解决此问题的最佳方法:

a) 创建多个 SQL 查询,分别运行它们并合并结果(类似于上面的代码),

b) 创建一个 SQL 查询(如果可能,最好的解决方案),

c) 别的东西(什么?)?

【问题讨论】:

  • 你真的在你的表名前加上table吗?您是否也在所有 Java 类的前面加上 Class

标签: java sql postgresql jpql


【解决方案1】:

主要有两种选择:

  1. 多个查询,每个传感器一个。这些可以单独执行,也可以通过UNION ALL 运算符捆绑在一起成为一个整体查询。后者可能是您最直接的选择。

  2. 但是,您也可以创建一个临时表,将传感器 ID 映射到所需的方位角,在该表上执行连接以过滤您的结果,然后删除该临时表。从 SQL 的角度来看,这具有一定的吸引力,但它有点深奥。它还需要至少三个单独的 SQL 语句(如果您的数据库不支持具有事务绑定生命周期的临时表,则需要四个)。

对应于备选方案 (1) 的查询可能是这样的:

SELECT s FROM Table_Sensor_Detection s
WHERE s.sensor_id = 1 AND s.azimuth = 10.0

UNION ALL

SELECT s FROM Table_Sensor_Detection s
WHERE s.sensor_id = 2 AND s.azimuth = 15.0

UNION ALL

-- ...

【讨论】:

【解决方案2】:

简单的方法是构建一个包含两列的IN 列表:

SELECT *
FROM Table_Sensor_Detection 
WHERE (sensor_id, azimuth) IN ( (1, 10.0), (2, 15.0), .... )

根据您的示例代码,您应该能够建立该条件。

大型IN 列表(“数百”个值)通常非常慢。一个更好的方法是建立一个长的values 子句,然后将它加入到表中:

SELECT s.*
FROM Sensor_Detection s
  JOIN (
     values (1, 10.0), (2, 15.0) 
  ) as t (id, azm)
  ON s.sensor_id = t.id AND s.azimuth = t.azm;

SQLFiddle:http://sqlfiddle.com/#!15/77c28/1


不相关但:确保您的 azimuth 列定义为 numericdecimal 并且 定义为 float - 否则您可能无法得到您想要的。

【讨论】:

    【解决方案3】:

    我从讨论开始就解决了我的算法问题;我为每个传感器和该传感器的方位角创建一个 SQL 查询,最后我将每个查询的结果合并到单个 ArrayList 中。

    这可行,但我想知道是否有更好的单 SQL 查询设计?

    正如我所见,理查德的回答并没有解决问题,因为我仍然需要多个查询。我正在寻找的是单个高级 SQL 查询。

    【讨论】:

    • 我提供的查询有什么问题?它将提供在 Java 和数据库之间的一次往返中完成这项工作,这似乎是您所追求的主要内容。
    【解决方案4】:
        CREATE FUNCTION dbo.IdentifyIfInRange 
        (
            -- Add the parameters for the function here
            @Field1 float
            ,@Field2 float
            ,@low float
            ,@high float
        )
        RETURNS float
        AS
        BEGIN
            -- Declare the return variable here
            DECLARE @ResultVar float
            SET @ResultVar = NULL
            -- Add the T-SQL statements to compute the return value here
            IF @Field2 BETWEEN @low and @high
                BEGIN 
                    SET @ResultVar=@Field1 
                END
            -- Return the result of the function
            RETURN @ResultVar
    
        END
    
    -- Do a join:
    
            SELECT Table_Sensor.sensor_id
             , Table_Sensor.sensor_name
             , Table_Sensor_Detection.azimuth
             , dbo.IdentifyIfInRange( 
        Table_Sensor_Detection.azimuth || Table_Sensor.sensor_id, Table_Sensor_Detection.azimuth, low_degs, high_degs ) AS acceptable_azimuth_or_id
            FROM Table_Sensor 
             INNER JOIN Table_Sensor_Detection 
              ON Table_Sensor_Detection.sensor_id= Table_Sensor.sensor_id
            WHERE Table_Sensor.sensor_id IN ( sensor_ids )
    
    -- OR TO Limit to only the acceptable sensorset
    
            SELECT Table_Sensor.sensor_id
             , Table_Sensor.sensor_name
             , Table_Sensor_Detection.azimuth
            FROM Table_Sensor 
             INNER JOIN Table_Sensor_Detection 
              ON Table_Sensor_Detection.sensor_id= Table_Sensor.sensor_id
            WHERE Table_Sensor.sensor_id IN ( sensor_ids ) and Table_Sensor.sensor_id = dbo.IdentifyIfInRange( Table_Sensor.sensor_id, Table_Sensor_Detection.azimuth, low_degs, high_degs )
    

    执行 LEFT OUTER JOIN 以从 Table_Sensor 获取所有信息,即使 Table_Sensor_Detection 不存在

    执行 Right OUTER JOIN 以从 Table_Sensor_Detection 中获取所有信息,即使 Table_Sensor 不存在也是如此

    【讨论】:

    • 这并没有真正回答问题,它询问如何仅选择具有特定检测方位角的行,该检测方位角因检测器而异。
    • 事实上,它根本没有回答这个问题,因为查询根本不需要(似乎)需要来自表 sensor 的任何内容。
    • 糟糕,我以为您可以在自己的“WHERE Table_Sensor.sensor_id IN (sensor_ids)”中添加过滤器
    • 对不起,这没有帮助。问题是我要比较的方位角取决于传感器。
    • 如您所描述的使用IN 的查询可能是有效的,但它不能解决问题,因为它不会过滤掉所有带有不需要的方位角的测量值。由于所需的方位角因传感器而异,因此您需要一个 (sensor_id, desired_azimuth) 表来使用 join 解决此问题。
    猜你喜欢
    • 2019-11-05
    • 1970-01-01
    • 2020-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多