Get entire record with max field for each group - postgresql

There are a lot of answers about this problem, but none of them retrieves the entire record, but only the ID... and I need the whole record.
So, I have a table status_changes that is composed of 4 columns:
issue_id : the issue the change refers to
id: the id of the change, just a SERIAL
status_from and status_to that are infact the status that the issue had before, and the status that the issue got then
when that is a timestamp of when this happened
Nothing too crazy, but now, I would like to have the "most recent status_change" for each issue.
I tried something like:
select id
from change
group by issue_id
having when = max(when)
But this has obviously 2 big problems:
select contains fields that are not in the group by
2 having can't contains aggregate function in this way
I thought of "ordering every group by when and using something like top(1), but I can't figure out how to do it...

Use PostgreSQL's DISTINCT ON:
SELECT DISTINCT ON (issue_id)
id, issue_id, status_from, statue_to, when
FROM change
ORDER BY issue_id, when DESC;
This will return the first result (the one with the greatest when) for each issue.

Related

Postgres SELECT id LAG(id) OVER (ORDER BY id) FROM invoice WHERE id = 2

I've looked all over the internet and I fail to get this query running as expected.
I've got a table of invoices and some invoices are related to one another because they belong to the same project.
My ticket says I've got to get the PREVIOUS invoice based on a provided invoice.
Say Project A has 10 invoices, and I'm looking at invoice #4, I've got to write a query which will return the ID of the previous Invoice. Bear in mind, the invoice table is home to all sorts of projects, and each project could have many invoices on their own, so I want to avoid getting many IDs back and then iterating over them.
To illustrate the issue, I've written this fiddle.
It works somewhat acceptably when I don't filter for steps.id, but that means returning hundreds of IDs to sift through.
I've tried and tried but I can't seem to get the column previousStep to be kind of bound to the ID column.
Simply find the invoice with the next largest id for the same project:
SELECT inv2.id
FROM invoice AS inv1
JOIN invoice AS inv2
ON inv1.project = inv2.project AND inv1.id > inv2.id
WHERE inv1.id = 1057638
ORDER BY inv2.id DESC
LIMIT 1;

Is there a way to sort influxDb by a field value other than time?

I'm trying to sort results from influxdb query but I can't get it to sort by anything other than time.
this works
SELECT last("value") FROM "table" WHERE $timeFilter GROUP BY "tag" ORDER BY "time" DESC
but this does not work
SELECT last("value") FROM "table" WHERE $timeFilter GROUP BY "tag" ORDER BY "value2" DESC
Anyone have any ideas?
Thanks!
Since sorting is only possible for the timestamp and tags, you might think about using a tag instead of a field for value2. But beware that this is only reasonable if the content of the newly created tag is not too variable. Otherwise you might kill influxDB with too many timeseries.
Details to be found here: https://docs.influxdata.com/influxdb/v1.7/concepts/schema_and_data_layout/
A different option could be to SELECT all data and to sort "manually" – in your code. But if that is reasonable depends on the usecase and the amount of data you get.
Ordering by something else than 'time' is unfortunately not allowed at this time. Maybe in the future...
https://github.com/influxdata/influxdb/issues/3954

MS-Access, Continuous form of multiple clients - Form.Text field containing Last Communication for Each Client / Customer in List

I am a First time user of StackOverFlow here!
I have been trying to figure this out for two days and have come up short.
We have a form that displays every single Client / Customer that we have at the firm, in a continuous form view.
We want to be able to display on this form the date, for each client, when we last communicated, or called, the client. (We want to be sure that we prevent a situation where we have not called a client for more than 1.5 months).
I have a query on a table tracking our correspondence, and other activities, regarding our clients that, in SQL, looks like:
' Query ContactCommunications
SELECT Context, ID, NoteDate, ContactID
FROM Comments
WHERE (((Context)="Communication with Client" Or (Context)="Phone Call with Client"));
(ContactID is a secondary key for Contacts table - we are tracking not
only clients but also opposing parties and such)
This is intended to show all the dates we called or communicated with our clients.
I have a second query that then gets the Last Date from this table, grouped by ContactID, which looks like:
' Query qryLastCommunicationAgg
SELECT ContactID, Last(CommentDate) AS LastOfCommentDate
FROM Comments INNER JOIN qryContactCommunications
ON Comments.ID = qryContactCommunications.ID
GROUP BY Comments.ContactID;
My question is how do I get the query result (When we last called each client) into a text field in our Continuous form list? At the moment there will be some null values as well.
I have tried the expression:
=DLookUp("CommentDate","qryLastCommunicationAgg",[ID]=[ContactID])
But it does not work, giving me #Name?
Not sure what I did wrong. :-(
I appreciate greatly any assistance or suggestions!
-Glenn
First, use Max:
SELECT ContactID, Max(CommentDate) AS LastOfCommentDate
Then try with:
=DLookUp("LastCommentDate","qryLastCommunicationAgg","[ID]=" & [ContactID] & "")
("Below is the fixed version of the DLookup script - Glenn")
=DLookUp("LastOfCommentDate","qryLastCommunicationAgg","[ContactID]=" & [ID] & "")

TSQL - Deleting with Inner Joins and multiple conditions

My question is a variation on one already asked and answered (TSQL Delete Using Inner Joins) but I have a different level of complexity and I couldn't see a solution to it.
My requirement is to delete Special Prices which haven't been accessed in 90 days. Special Prices are keyed on Customer ID and Product ID and the products have to matched to a Customer Order Detail table which also contains a Customer ID and a Product ID. I want to write one function that will look at the Special Price table for each Customer, compare each Product for that Customer with the Customer Order Detail table and if the Maximum Order Date is more than 90 days earlier than today, delete it from the Special Price table.
I know I can use a CURSOR (slow but effective) but would prefer to have a single query like the one in the TSQL Delete Using Inner Joins example. Any ideas and/or is more information required?
I cannot dig more on the situation of your system but i think and if it is ok for you, check MERGE STATEMENT, it might be a help instead of using cursors. check this Link MERGE STATEMENT

TSQL Merge Insert With Duplicate

I have a table that has duplicate email address, I need to insert just one of them into a temp a temp table along with two other fields. there are many example here but I can get any of them work,
I ended up looking into MERGE I get the same results. All the record are getting inserted I'm at a lost. I tried many different samples but it always insert all the records. I went back to make sure the email address are really dupes and they are.. Below is were I'm at now..
MERGE #EmailTable2 AS Target
USING (SELECT EMAIL, NAME, JOB_TITLE FROM b2b_cmas_list$ WHERE EMAIL IS NOT NULL) AS Source
ON (Target.EMAIL = Source.EMAIL)
WHEN NOT MATCHED BY TARGET THEN
INSERT (EMAIL, NAME, JOB_TITLE)
VALUES (Source.EMAIL, Source.NAME, Source.JOB_TITLE)
OUTPUT $action, inserted.*, deleted.*;
so any help in getting this correct would be helpful.
This it not working because SQL doesn't know, which of the two rows containing the same e-mail you want to choose. I mean: if EMAIL is the same, which of pair (NAME and JOB_TITLE) are important and which can be discarded?
Some hints:
If it doesn't matter which item is chosen simply group by EMAIL selecting MAX(NAME) and MAX(JOB_TITLE), i.e.
select EMAIL, max(NAME), max(JOB_TITLE) from b2b_cmas_list$ group by EMAIL
Be warned however that this can mangle NAME-JOB_TITLE pairs (as max is selected).
Try using ROW_NUMBER() OVER() to arbitrarilly select 1st row in each group.
Use a CURSOR to iterate over rows and skip duplicates.
Use .NET CLR aggregate to i.e. concat names and job titles for same e-mail.
And a little note to your MERGE statement. This is not working as expected, because SQL checks all rows at once, and not row-by-row. So it is not that if one e-mail. ie. "a#a.com" is inserted, then another won't. It only matters if "a#a.com" is in the table at the beginning of the statement.