views:

163

answers:

3

i have some SQL code that is inserting values from another (non sql-based) system. one of the values i get is a timestamp.

i can get multiple inserts that have the same timestamp (albeit different values for other fields).

my problem is that i am trying to get the first insert happening every day (based upon timestamp) since a particular day (i.e. give me the first insert of each day since January 28, 2007...)

my code to get the first timestamp of every day is as follows:

SELECT MIN(my_timestamp) AS first_timestamp
FROM my_schema.my_table
WHERE my_col1 = 'WHATEVER'
AND my_timestamp > timestamp '2010-Jul-27 07:45:24' - INTERVAL '365 DAY'
GROUP BY DATE (my_timestamp);

This delivers me the list of times available. But when I join against these times, I can get several rows, as there are lots of rows that mach these times. So for 365 days, I may get 5,000 rows (I could be inserting 100 rows at 00:00:00 every day).

Assuming, in the example above, my_table has columns my_col1 and my_col2, how can I get exactly 365 rows that contain my_col1 & my_col2? it doesn't matter which row i get back if there are multiple rows for a date; any row will suffice.

it's an odd question. the overall problem is: given a timestamp, how can one get 1-row-per-timestamp even if there are multiple rows that have said timestamp (assuming there is no other priority)?

thanks for the help in advance.

EDIT: So, let's say for example, this table has the following columns: my_col1, my_col2, and my_timestamp.
Here are example values (in order of my_col1 - my_col2 - my_timestamp):

  • 'my_val1' - 10 - '2010-07-01 01:01:01'
  • 'my_val2' - 11 - '2010-07-01 01:01:01'
  • 'my_val3' - 12 - '2010-07-01 01:01:01'
  • 'my_val4' - 13 - '2010-07-01 01:01:02'
  • 'my_val5' - 14 - '2010-07-02 01:01:01'
  • 'my_val6' - 15 - '2010-07-02 01:01:01'
  • 'my_val7' - 16 - '2010-07-03 01:01:01'

in the end, i would want only 3 rows, 1 with a timestamp with '2010-07-01 01:01:01', one with '2010-07-02 01:01:01', and one with '2010-07-03 01:01:01'. the third one is easy, since there is only 1 row with that last timestamp. but the first two are the tricky ones. the sql i posted above will ignore the row with 'my_val4'.

i need a query that will return me all of the columns, not just the dates.

how would i get sql to give me either the first or last of the values that would match that timestamp (it doesn't matter either way. i just need to get 1-per first-day's timestamp matching)?

+1  A: 

The solution is to use the SQL's DISTINCT statement (http://www.sql-tutorial.com/sql-distinct-sql-tutorial/):

SELECT DISTINCT MIN(my_timestamp) AS first_timestamp FROM my_schema.my_table WHERE my_col1 = 'WHATEVER' AND my_timestamp > timestamp '2010-Jul-27 07:45:24' - INTERVAL '365 DAY' GROUP BY DATE (my_timestamp);
dark_charlie
i'm already getting distinct rows when it comes to the date. in your sql here, the 'distinct' keyword does nothing (redundant). the 'group by' solves that problem.there needs to be a join with the SQL i gave above, but i don't know what to join to get what i want.
okie.floyd
okie.floyd
Sorry, misunderstood your question in this. Could you please specify how the table you want to join with this one looks like?
dark_charlie
+3  A: 
select distinct on (date(my_timestamp)) *
from my_table
order by date(my_timestamp), my_timestamp

This selects all columns, exactly one row per date(my_timestamp). The single row per day is the first row for the group, as determined by order by (so that's the row with minimal my_timestamp).

Of course you can add whatever joins, wheres etc. you need. But this is the stub you're looking for.

Konrad Garus
you nailed it. well done. very elegant solution.
okie.floyd
A: 

I know you already have an answer, but I still don't understand why you have mentioned a join in your question. Why not just include the rest of the columns in your query, like this:

SELECT MIN(my_timestamp) AS first_timestamp, my_col1, my_col2
FROM my_table
GROUP BY DATE(my_timestamp);

This works in MySQL. Does it not return the expected result in PostgreSQL?

Mike
no. 'GROUP BY' in Postgres doesn't work this way. You have to do a 'Group By' for every element you are trying to select, which essentially means you are trying to do a "distinct" on all 3 fields, which isn't the desired result. thanks for the input.
okie.floyd