Extracting key from the value of json object in postgres - sql

Let us say I have a json object {'key1':0.5,'key2':0.3,'key3':0.1} in a particular column in a table called test. I want to return the key of the highest value. To get the highest value, in postgres, I can write this query:
select greatest(column1->'key1',column1->'key2',column1->'key3') from test
Now, it returns the greatest value. But the one I want is the key associated with the highest value. Is this possible in postgres json querying?

You need to extract all key/value pairs as rows. Once you have done that, it's a greatest-n-per-group problem - without the "group" though as you are looking at all rows.
select k,val
from (
select t.*, row_number() over (order by t.val::numeric desc) as rn
from jsonb_each_text('{"key1":0.5,"key2":0.3,"key3":0.1}'::jsonb) as t(k,val)
) t
where rn = 1;
Online example: http://rextester.com/OLBM23414

Related

SQL - Retrieve Associated Primary Key and Value of MAX(value) of Query

I have an SQL problem in regards to selecting a max value in a table/query. I am trying to return the maximum value returned from an aggregate expression as well as the associated primary key of the tuple.
I am able to return 1 tuple displaying only the maximum value when I only include the aggregate function in the select statement but I am unable to return just 1 tuple with BOTH the primary key and the max value of the aggregate expression.
Here is an example of my query:
SELECT id, MAX(SQRT((POWER((x-(-28)),2) + POWER((y-(151)),2)))) as distance
FROM table
GROUP BY id;
As you would expect this returns all the id's and the associated value from the function. It doesn't return just 1 tuple with the maximum value and the associated id.
What can I do to fix this?
One way to do this is by ordering by your expression in descending order, and only selecting the first row:
select id, distance
from (select id, SQRT((POWER((x-(-28)),2) + POWER((y-(151)),2))) as distance
from table
order by distance desc)
where rownum < 2
Starting with Oracle 12c, you can also take advantage of the fetch first n rows syntax to accomplish the same thing:
select id, SQRT((POWER((x-(-28)),2) + POWER((y-(151)),2))) as distance
from table
order by distance desc
fetch first row only
If more than one row shares the same maximum distance value, you can also conveniently adjust the syntax to support ties:
select id, SQRT((POWER((x-(-28)),2) + POWER((y-(151)),2))) as distance
from table
order by distance desc
fetch first row with ties

ORACLE SQL - Need query to return one row (ID exists multiple times)

In need of some assistance... I've tried for awhile and can't get what I need. (it's going to be used as a sub query within the FROM statement of another query) that will return the creator ID and 1 note. I only need ONE row returned per ID. (Can be any of the notes that matches the creator ID -- doesn't matter) The creator ID is a key that shows up multiple times in the table.
Here is one way:
select t.*
from (select t.*, row_number() over (partition by creator order by ordnum) as seqnum
from notes t
) t
where seqnum = 1;

Need To Pull Most Recent Record By Timestamp Per Unique ID

I'm going to apologize up front, this is my first question on stackoverflow...
I am attempting to query a table of records where each row has a VehicleID, latitude, longitude, timestamp and various other fields. What I need is to only pull the most recent latitude and longitude for each VehicleID.
edit: removed the term unique ID as apparently I was using it incorrectly.
If the Unique ID is truely unique, then you will always have the most recent latitude and longitude, because the ID will change with every singe row.
If the Unique ID is a Foreign Key (or an ID referencing a unique ID from a different table) you should do something like this:
SELECT latitude, longitude, unique_id
FROM table INNER JOIN
(SELECT unique_id, MAX(timestamp) AS timestamp
FROM table
GROUP BY unique_id)t2 ON table.timestamp = t2.timestamp
AND table.unique_id = t2.unique_id;
You can use the row_number() function for this purpose:
select id, latitude, longitude, timestamp, . . .
from (select t.*,
row_number() over (partition by id order by timestamp desc) as seqnum
from t
) t
where seqnum = 1
The row_number() function assigns a sequential value to each id (partition by clause), with the most recent time stamp getting the value of 1 (the order by clause). The outer where just chooses this one value.
This is an example of a window function, which I encourage you to learn more about.
One quibble with your question: you describe the id as unique. However, if there are multiple values at different times, then it is not unique.
Check this link to implement row indexes and utilize the partition to reset per group. Then in your WHERE clause filter out the results that aren't the first.

Interview - Detect/remove duplicate entries

how to detect/remove duplicate entries from a database in a table where there is no primary key ?
[If we use 'DISTINCT' how do we know which record is the correct one and duplicate one ? ]
delete f
from
(
select ROW_NUMBER()
over (partition by
YourFirstPossibleDuplicateField,
YourSecondPossibleDuplicateField
order by WhateverFieldYouWantSortedBy) as DelId
from YourTable
) as f
where DelId > 1
I created a view where DISTINCT actually was not a part of the query, but PARTITION. I needed the most recent entry to records with the same Ordernum and RecordType fields, discarding the others. The partitions are ordered by date, and then the top row is selected, like this:
SELECT *, ROW_NUMBER()
OVER (PARTITION BY OrderNum, RecordType ORDER BY DateChanged DESC) rn
FROM HistoryTable SELECT * FROM q WHERE rn = 1
If we use 'DISTINCT' how do we know which record is the correct one
and duplicate one?
If you have duplicate rows then doesn't matter which duplicate is picked because they are all the same!
I guess when you say "there is no primary key" that you actually mean there is no simple single-column 'surrogate' candidate key such as an incrementing sequence of integers, preferably with no gaps, but that there is a multi-column compound 'natural' candidate key (though does not comprise all the columns).
If this is the case, you'd look for something to break ties e.g. a column named DateChanged as per #Dave's answer. Otherwise, you need to pick am arbitrary row e.g. the answer by #Surfer513 does this using the ROW_NUMBER() windowed function over (YourFirstPossibleDuplicateField, YourSecondPossibleDuplicateField) (i.e. your natural key) then picking the duplicate that got arbitrarily assigned the row number 1.

SQL Max Function per group

I have a complex query and which may return more than one record per group. There is a field that has a numeric sequential number. If in a group there is more than one record returned I just want the record with the highest sequential number.
I’ve tried using the SQL MAX function, but if I try to add more than one field it returns all records, instead of the one with the highest sequential field in that group.
I am trying to accomplish this in MS Access.
Edit: 4/5/11
Trying to create a table as an example of what I am trying to do
I have the following table:
tblItemTrans
ItemID(PK)
Eventseq(PK)
ItemTypeID
UserID
Eventseq is a number field that increments for each ItemID. (Don’t ask me why, that’s how the table was created.) Each ItemID can have one or many Evenseq’s. I only need the last record (max(Eventseq)) PER each ItemTypeID.
Hope this helps any.
SELECT A.*
FROM YourTable A
INNER JOIN (SELECT GroupColumn, MAX(SequentialColumn) MaxSeq
FROM YourTable
GROUP BY GroupColumn) B
ON A.GroupColumn = B.GroupColumn AND A.SequentialColumn = B.MaxSeq
If your SequentialNumber is an ID (unique across the table), then you could use
select *
from tbl
where seqnum in (
select max(seqnum) from tbl
group by groupcolumn)
If it is not, an alternative to Lamak's query is the Access domain function DMAX
select *
from tbl
where seqnum = DMAX("seqnum", "tbl", "groupcolumn='" & groupcolumn & "'")
Note: if the groupcolumn is a date, use # instead of single quotes ' in the above, if it is a numeric, remove the single quotes.