English 中文(简体)
SQL query to get the "latest" value for each location
原标题:
  • 时间:2009-11-23 15:39:08
  •  标签:
  • sql
  • informix

What I thought would be a simple thing to solve has now bugged for quite some time. Now I need help from you guys.

In Informix I have a table "temperatures" like this:

locId    dtg               temp
100      2009-02-25 10:00  15
200      2009-02-25 10:00  20
300      2009-02-25 10:00  24
100      2009-02-25 09:45  13
300      2009-02-25 09:45  16
200      2009-02-25 09:45  18
400      2009-02-25 09:45  12
100      2009-02-25 09:30  11
300      2009-02-25 09:30  14
200      2009-02-25 09:30  15
400      2009-02-25 09:30  10

I am trying to get the latest temp for each locId that has updated values within the last 20 min.

So the result I want from the table above would be (say I run the query at 2009-02-25 10:10):

locId    dtg               temp
100      2009-02-25 10:00  15
200      2009-02-25 10:00  20
300      2009-02-25 10:00  24

One more thing that complicates things is that I would like to be able to supply a list on locId that should be selected. I mean use something like "...locId IN (100,200,400)..."

I have tried to use a join on a sub query (as suggested in SQL Query to get latest price ) but I can´t get it to work. Not even without the extra "update within the last 20 min".

select t.*
from temperatures as t
 JOIN (select locId, max(dtg) from temperatures where locId IN (100,200,400)  group by locId) as l 
    on l.locId=t.locId and l.dtg=t.dtg
where locId in (100,200,400)

This query gives me SQL error but I cant find error. Is there an error I can´t find or is this way to do it not possible in Informix.

Or is there some other way to go? All help appreciated.

问题回答

Your SQL errors can be corrected using the following syntax:

SELECT t.*
FROM temperatures AS t
INNER JOIN (
    SELECT locId, MAX(dtg) AS maxdtg 
    FROM temperatures 
    WHERE locId IN (100,200,400)  GROUP BY locId
) AS l 
ON l.locId = t.locId AND maxdtg = t.dtg
WHERE t.locId IN (100,200,400)

EDIT: Also, one proper and more dynamic way to go about this:

SELECT t2.* FROM (
    SELECT locId, MAX(dtg) AS maxdtg 
    FROM temperatures 
    GROUP BY locId
) t1
INNER JOIN (
    SELECT locId, dtg, temp 
    FROM temperatures
) t2 
ON t2.locId = t1.locId 
    AND t2.dtg = t1.maxdtg
WHERE t2.dtg > CURRENT YEAR TO MINUTE - 20 UNITS MINUTE

EDIT: Was looking for posts more than 20 minutes in the future instead of 20 minutes old... oops!

EDIT AGAIN: Forgot this was for Informix database... gave MSSQL syntax for where clause.

You need to name the max(dtg) column in the subselect - your query just matches all rows by time not just the latest.

select t1.locId, t1.temp, time
   from temperatures t1
      inner join ( select t1.locId, t1.temp, max(t1.dtg) as time
                     from temperatures group by t1.locId, t1.temp) as t2
        on t1.locId = t2.locId
           and t1.dtg = t2.time
    where t1.locId in (100,200,400)

You can add the where condition inside the sub select as well and also you could add a condition to get only the readings in the last 20 minutes.

edit: as per comment - I had typed the wrong join and other errors.


Some assistance - the references to t1 in the sub-query are wrong. You need an extra table reference (t3):

select t1.locId, t1.temp, time
   from temperatures t1
        inner join (select t3.locId, t3.temp, max(t3.dtg) as time
                      from temperatures as t3 group by t3.locId, t3.temp) as t2
                        on t1.locId = t2.locId and t1.dtg = t2.time
    where t1.locId in (100,200,400)

This yields the result:

100    15    2009-02-25 10:00
200    20    2009-02-25 10:00
100    13    2009-02-25 09:45
200    18    2009-02-25 09:45
400    12    2009-02-25 09:45
100    11    2009-02-25 09:30
200    15    2009-02-25 09:30
400    10    2009-02-25 09:30

Unfortunately, this is not the required result, though it is getting closer. Part of the trouble is that you don t want t3.temp in the sub-select or its GROUP BY clause.

I chose to create a one-row table RefDateTime to hold the reference time (2009-02-25 10:10). There are other ways to handle that - notably writing `DATETIME(2009-02-25 10:10) YEAR TO MINUTE.

CREATE TABLE temperatures
(
    locId   INTEGER NOT NULL,
    dtg     DATETIME YEAR TO MINUTE NOT NULL,
    temp    INTEGER NOT NULL
);

INSERT INTO Temperatures VALUES(100,  2009-02-25 10:00 , 15);
INSERT INTO Temperatures VALUES(200,  2009-02-25 10:00 , 20);
INSERT INTO Temperatures VALUES(300,  2009-02-25 10:00 , 24);
INSERT INTO Temperatures VALUES(100,  2009-02-25 09:45 , 13);
INSERT INTO Temperatures VALUES(300,  2009-02-25 09:45 , 16);
INSERT INTO Temperatures VALUES(200,  2009-02-25 09:45 , 18);
INSERT INTO Temperatures VALUES(400,  2009-02-25 09:45 , 12);
INSERT INTO Temperatures VALUES(100,  2009-02-25 09:30 , 11);
INSERT INTO Temperatures VALUES(300,  2009-02-25 09:30 , 14);
INSERT INTO Temperatures VALUES(200,  2009-02-25 09:30 , 15);
INSERT INTO Temperatures VALUES(400,  2009-02-25 09:30 , 10);

CREATE TABLE RefDateTime
(
    reftime DATETIME YEAR TO MINUTE NOT NULL
);
INSERT INTO RefDateTime VALUES( 2009-02-25 10:10 );

SELECT t1.locID, t1.dtg, t1.temp
  FROM temperatures AS t1 JOIN
    (SELECT t2.locID, MAX(t2.dtg) AS latest
        FROM temperatures AS t2
       WHERE t2.dtg > (SELECT RefTime - 20 UNITS MINUTE FROM RefDateTime)
         AND t2.locID IN (100, 200, 400)
       GROUP BY t2.locID) AS t3 ON t1.locID = t3.locID AND t1.dtg = t3.latest
;

This gives what I believe is the correct result:

100     2009-02-25 10:00      15
200     2009-02-25 10:00      20

When the t2.locID IN (100, 200, 400) condition is omitted, it also shows the row with the locID of 300 (and temperature of 24).





相关问题
SQL SubQuery getting particular column

I noticed that there were some threads with similar questions, and I did look through them but did not really get a convincing answer. Here s my question: The subquery below returns a Table with 3 ...

难以执行 REGEXP_SUBSTR

I m 查询Oracle 10g。 我有两张表格(样本数据见下文)。 i m 试图提取一些领域

SQL Query Shortcuts

What are some cool SQL shorthands that you know of? For example, something I learned today is you can specify to group by an index: SELECT col1, col2 FROM table GROUP BY 2 This will group by col2

PHP array callback functions for cleaning output

I have an array of output from a database. I am wondering what the cleanest way to filter the values is example array Array ( [0] => Array ( [title] => title 1 ...

OracleParameter and DBNull.Value

we have a table in an Oracle Database which contains a column with the type Char(3 Byte). Now we use a parameterized sql to select some rows with a DBNull.Value and it doesn t work: OracleCommand ...

Running numbers in SQL

I have a SQL-statement like this: SELECT name FROM users WHERE deleted = 0; How can i create a result set with a running number in the first row? So the result would look like this: 1 Name_1 2 ...

How to get SQL queries for each user where env is production

I’m developing an application dedicated to generate statistical reports, I would like that user after saving their stat report they save sql queries too. To do that I wrote the following module: ...

热门标签