Select jsonb key which has the highest value compare to other keys - sql

I have this jsonb column with name "demographics" . It looks like this
{
"genre":{"women":10,"men":5}
}
I am trying to create new column which will pick the json key name of the one with highest value;
I tried this.
SELECT Greatest(demographics -> 'genre' ->> 'men',
demographics -> 'genre' ->> 'women')
AS greatest
FROM demographics;
This one will get "value" of the highest one but i want the key name and not the value.
Basically i want that it returns in this case to the row "women" as it has higher value;

You can unpack the json object at genre to individual rows using jsonb_each and then get the greatest value using row_number or any number of methods:
with cte as
(
select *
, genre.key as genre
, row_number() over (partition by id order by value desc) as ord
from demographics
cross
join lateral jsonb_each(demographics->'genre') genre
)
select id, genre, value
from cte
where ord = 1
Here's a working demo on dbfiddle

Related

How to get the Distinct Record in Sql Server

How can I display all records in a single coulmn if the name is duplicate in sql server.
SELECT * INTO #temp
FROM (
Select 'S1' Name, '1' Age, 'A' X, 'B' Y UNION ALL
Select 'S1', '1', '', 'B'
) A
Select *
From #temp
[Output]
The expected result is:
The rules for the expected output aren't clear. It could be the "last" row based on some order, or each column returns the maximum value in a group.
If the maximum value is needed, the following should work:
SELECT Name, Max(Age) as Age, Max(X) as X, Max(Y) as Y
FROM SomeTable
GROUP BY Name
If the "last" row is needed, there must be a way to order the results. Table rows have no implicit order. Assuming there's an incrementing ID, one could use ROW_NUMBER to find and return the latest row per group:
with rows as
(
SELECT ID,Name,Age,X,Y,ROW_NUMBER(PARTITION BY Name ORDER BY ID DESC) as RN
FROM SomeTable
)
SELECT Name,Age,X,Y
FROM rows
WHERE RN=1
This will split (partition) the data by name and calculate a row_number based on descending order inside each partition. Since the rows are ordered by ID descending, the first row will the the latest one.

Getting MAX of a column and adding one more

I'm trying to make an SQL query that returns the greatest number from a column and its respective id.
For more information I have two columns ID and NUMBER. Both of them have 2 entries and I want to get the highest number with the ID next to it. This is what I tried but didn't success.
SELECT ID, MAX(NUMBER) AS MAXNUMB
FROM TABLE1
GROUP BY ID, MAXNUMB;
The problem I'm experiencing is that it just shows ALL the entries and if I add a "where" expression it just shows the same (all entries [ids+numbers]).
Pd.: Yes, I got what I wanted but only with one column (number) if I add another column (ID) to select it "brokes".
Try:
SELECT
ID,
A_NUMBER
FROM TABLE1
WHERE A_NUMBER = (
SELECT MAX(A_NUMBER)
FROM TABLE1);
Presuming you want the IDs* of the row with the highest number (and not, instead, the highest number for each ID -- if IDs were not unique in your table, for example).
* there may be more than one ID returned if there are two or more IDs with equal maximum numbers
you can try this
Select ID,maxNumber
From
(
SELECT
ID,
(Select Max(NUMBER) from Tmp where Id = t.Id) maxNumber
FROM
Tmp t
)T1
Group By ID,maxNumber
The query you posted has an illegal column name (number) and is group by the alias for the max value, which is illegal and also doesn't make sense; and you can't include the unaliased max() within the group-by either. So it's likely you're actually doing something like:
select id, max(numb) as maxnumb
from table1
group by id;
which will give one row per ID, with the maximum numb (which is the new name I've made up for your numeric column) for each ID. Or as you said you get "ALL the entries" you might have group by id, numb, which would show all rows from the table (unless there are duplicate combinations).
To get the maximum numb and the corresponding id you could group by id only, order by descending maxnumb, and then return the first row only:
select id, max(numb) as maxnumb
from table1
group by id
order by maxnumb desc
fetch first 1 row only
If there are two ID with the same maxnumb then you would only get one of them - and which one is indeterminate unless you modify the order by - but in that case you might prefer to use first 1 row with ties to see them all.
You could achieve the same thing with a subquery and analytic function to generating a ranking, and have the outer query return the highest-ranking row(s):
select id, numb as maxnumb
from (
select id, numb, dense_rank() over (order by numb desc) as rnk
from table1
)
where rnk = 1
You could also use keep to get the same result as first 1 row only:
select max(id) keep (dense_rank last order by numb) as id, max(numb) as maxnumb
from table1
fiddle

How to generate random UUID per group of records in postgres

HOw can i create random UUID per group of records ?
for ex, how can I create random uuid per name(diff in color) in below dataset in Postgres sql ?
First, you need uuid-ossp to generate uuids. This is a module you need to add in.
Then it should be pretty simple method would be:
select t.*, name_uuid
from t join
(select name, uuid_generate_v4() as name_uuid
from t
group by name
) n
using (name);
Generate UUID for all rows, then use max(id) over(partition by name) to get the same id for group.
select max(id) over (partition by name) as id, name, age
from
(
select name, age, md5(random()::text || clock_timestamp()::text)::uuid as id
from ...
)s
Also can use uuid-ossp for UUID generation like in #GordonLinoff answer

How to delete the duplicate data in table (Postgres)

I want to delete the duplicated data in a table , I know there is a way use
SELECT
fruit,
COUNT( fruit )
FROM
basket
GROUP BY
fruit
HAVING
COUNT( fruit )> 1
ORDER BY
fruit;
to find them , buy I need to determine every column's value is equal , which means tableA.* = tableA.* (except id , id is the auto-increment primary key )
and I tried this:
SELECT
*,
COUNT( * )
FROM
myTable
GROUP BY
*
HAVING
COUNT( * )> 1
ORDER BY
id;
but it says I can't use GROUP BY * , so how can I find & delete the duplicated data(need every column's value is equal except id)?
using
SELECT * DISTINCT
DISTINCT remove duplicated result
You need to try something similar to be below query. You apply PARTITION BY for the columns other than Id (as it is incrementing unique value). PARTITION BY should be applied for columns, for which you want to check duplicates.
Also refer to Row_Number in Postgres & Common Table expression in Postgres
WITH DuplicateTableRows AS
(
SELECT Id, Row_Number() OVER (PARTITION BY col1, col2... ORDER BY Id)
FROM
Table1
)
DELETE FROM Table1
WHERE Id IN (SELECT Id FROM Table1 WHERE row_number > 1)
You can do this using JSON:
select (to_jsonb(b) - 'id')
from basket b
group by 1
having count(*) > 1;
The result is as JSON. Unfortunately, to extract the values back into a record, you need to list the columns individually.

SQL Select a distinct row based on two columns which has min value in third column

EDIT: I'm using PostgresSQL
My query needs to return all the unique rows for the id column and the type column. When there are multiple rows with the same id and type it will return the row with the smallest value in the time column.
SELECT id, type, value FROM TableName
GROUP BY MIN(time)
ORDER BY id ASC, type ASC
This is what I have so far but I feel like I'm using GROUP BY the wrong way
I think you can use ROW_NUMBER to mark the rows within each combination of id and type with the smallest time having rn = 1, then use WHERE clause to filter the table:
SELECT id, type, value FROM
(SELECT id, type, value,
ROW_NUMBER() OVER(PARTITION BY id, type ORDER BY time) AS rn
FROM TableName) a
WHERE rn = 1
Postgres support distinct on. This is usually the most efficient way to do what you want:
SELECT DISTINCT ON (id, type) id, type, value
FROM TableName
ORDER BY id, type, time ;