1

Database:

Table_Sensor:
    sensor_id,
    sensor_name

Table_Sensor_Detection:
    sensor_id
    azimuth (azimuth from specific sensor)

Users have the possibility to enter multiple Sensors, so I have defined Set < Integer> sensorsSet.

Users also have the possibility to enter azimuth for each sensor, so i have Sensor.azimuth, for each sensor.

All I need is logic for SQL statement that will give me all sensor_detections for entered sensors_ids, and another query for the adequate azimuth for each sensor.

This is List< String> queryList that describe logic I want accomplish.

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

The code above is simplified, so don't bother with possible mistakes. I only want to found out what is best approach to solve this problem:

a) create multiple SQL queries, run them separately and merge results (similar to code above),

b) create one SQL query (best solution if it is possible),

c) something else (what?)?

Biswajit_86
  • 3,661
  • 2
  • 22
  • 36
frane
  • 65
  • 1
  • 7
  • Do you really prefix your table names with `table`? Do you prefix all your Java classes with `Class` as well? –  May 04 '15 at 06:16

4 Answers4

1

There are two main alternatives:

  1. Multiple queries, one for each sensor. These can be executed separately, or they can be bundled together into a single overall query via the UNION ALL operator. The latter would probably be the most straightforward alternative for you.

  2. However, you could also create a temporary table mapping sensor ids to desired azimuths, perform a join on that table to filter your results, and then drop the temp table. This has a certain appeal from an SQL perspective, but it's a little more esoteric. It also requires at least three separate SQL statements (four if your DB does not support temp tables with transaction-bound lifetime).

The query corresponding to alternative (1) might be along these lines:

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

-- ...
John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Sorry I missed this answer. I think this is solution, I'll try it. Two topics that can be helpful for UNION in JPQL: http://stackoverflow.com/questions/15062501/jpa-only-executes-first-select-statement-in-union http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/j_union.htm#union – frane May 04 '15 at 06:13
0

I solved problem with my algorithm from beginning of discussion; I create a SQL query for each sensor and azimuth for that sensor, and at the end I merge results from each query into single ArrayList.

This works, but I wonder is there a better design with single SQL query?

As I see Richard's answer doesn't solve problem because I would still need multiple queries. What I'm looking for is single advanced SQL query.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
frane
  • 65
  • 1
  • 7
  • And what's wrong with the query I offered? It would provide for doing the job in one round trip between Java and database, which seems to be the main thing you're after. – John Bollinger May 04 '15 at 13:43
0

The simple approach is to build an IN list with two columns:

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

Given your sample code you should be able to build up that condition.

Large IN lists ("hundreds" of values) are usually quite slow however. A better way to do this is to build up a long values clause and then join that to the table:

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


Unrelated but: make sure your azimuth column is defined as numeric or decimal and not as a float - otherwise you'll probably not get what you want.

-1
    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 )

Do a LEFT OUTER JOIN to get all from Table_Sensor even where Table_Sensor_Detection doesn't exist

Do a Right OUTER JOIN to get all from Table_Sensor_Detection even where Table_Sensor doesn't exist

  • This doesn't really answer the question, which asks how to select only rows having a specific detection azimuth that varies by detector. – John Bollinger May 03 '15 at 17:57
  • In fact, it doesn't answer the question at all, because the query does not (appear to) require anything from table `sensor` at all. – John Bollinger May 03 '15 at 17:59
  • My bad I thought you could add the filter on your own "WHERE Table_Sensor.sensor_id IN ( sensor_ids )" – Richard Taylor-Kenny May 03 '15 at 18:14
  • Sorry, this doesnt help. Problem is that my azimuth to compare depend on sensor. – frane May 03 '15 at 18:19
  • A query using `IN` as you describe could be valid, but it doesn't address the problem because it doesn't filter out all the measurements with unwanted azimuths. Since the wanted azimuths vary by sensor, you need a table of `(sensor_id, desired_azimuth)` to solve this problem with a `join`. – John Bollinger May 03 '15 at 18:19
  • I am not sure that table of (sensor_id, desired_azimuth) could be good approach because I can (and must) have multiple sensor_id in query, but I cannt have multiple azimuths... Somehow azimuth comparation must be done only on sensor_detections with specific sensor_id. I am not sure that this is even possible to do with single query. – frane May 03 '15 at 18:45
  • And why not also add the filter AND Table_Sensor_Detection.azimuth IN (acceptable_azimuths) ? – Richard Taylor-Kenny May 03 '15 at 18:51
  • Thankes Richard. Real situation is more complicated so "azimuth IN (acceptable_azimuths)", is solved already, what bother me is situation with azimuth that depend of sensor_id.. – frane May 03 '15 at 18:58
  • And why not also add the filter AND Table_Sensor_Detection.azimuth IN (acceptable_azimuths) ? If you need exact sensor_id/azimuth combinations then combine them first ( a function might be helpful) and do your filter on that returned value ie.(Table_Sensor.sensor_id + Table_Sensor_Detection.azimuth) as sensorid_azmuth ... where sensorid_azmuth in ( sensorid_azmuth_set ) Granted conversion might be necessary to combine the fields. – Richard Taylor-Kenny May 03 '15 at 19:05
  • I hope the modifications to my answer help otherwise I think I may have completely missed the desired result. The modified solution provides a way to identify a range for acceptable azimuths and limit the result set based on the sensor's azimuth meeting that test. – Richard Taylor-Kenny May 03 '15 at 21:19
  • This is invalid syntax for Postgres –  May 04 '15 at 06:06
  • @frane, "I am not sure that table of (sensor_id, desired_azimuth) could be good approach [...] Somehow azimuth comparation must be done only on sensor_detections with specific sensor_id." That objective is *exactly* what a temporary table of `(sensor_id, desired_azimuth)` could provide for you. You could (inner) join table `Table_Sensor_Detection` with both columns of the temp table to effect exactly the kind of filtering you describe. But you'd need extra statements to set up and possibly to drop the temp table. – John Bollinger May 04 '15 at 13:47