Sort by specific order, including NULL, postgresql - sql

best explained with an example:
So I have users table:
id name product
1 second NULL
2 first 27
3 first 27
4 last 6
5 second NULL
And I would like to order them in this product order: [27,NULL, 6]
So I will get:
id name product
2 first 27
3 first 27
1 second NULL
5 second NULL
4 last 6
(notice user id 3 can be before user id 2 since they both have the same product value)
Now without NULL I could do it like that:
SELECT id FROM users ORDER BY users.product=27, users.product=6;
How can I do it with NULL ?
p.s.
I would like to do that for many records so it should be efficient.

You can use case to produce custom sort order:
select id
from users
order by case
when product = 27
then 1
when product is null
then 2
when product = 6
then 3
end

As a note, you can follow your original approach. You just need a NULL-safe comparison:
SELECT id
FROM users
ORDER BY (NOT users.product IS DISTINCT FROM 27)::int DESC,
(user.product IS NULL)::int DESC,
(NOT users.product IS DISTINCT FROM 6)::int DESC;
The reason your version has unexpected results is because the first comparison can return NULL, which is ordered separately from the "true" and "false".

Related

SQL WHERE condition when one does not return true, then try other

I have to query a table based on two fields such that if first field matches then don't check the second but if first field does not match then check if second field matches for a value
something like:
SELECT * FROM table
WHERE cart_id=389 OR (cart_id IS NULL AND user_id=26)
But if first condition succeeds, it must not check for second condition
Example:
Suppose the following is my table
id | cart_id | user_id
1 | 389 | 26
2 | null | 26
3 | 878 | 26
on querying for cart_id = 389 and user_id = 26, I should get back only record 1 and NOT 2
on querying for cart_id = 1 and user_id = 26, I should get back only records 2 and NOT 1 and 3
The only way I can think of, is to do this in two steps and check the result of the first step in the second:
with the_cart as (
SELECT *
FROM the_table
WHERE cart_id=389
)
select *
from the_cart
union all
select *
from the_table
where cart_id IS NULL
AND user_id=26
and not exists (select * from the_cart);
If the first query (using cart_id=389) returns something the second query from the union will not be run (or more precisely return no rows) due to the not exists() condition.
Online example
Based on your updated example data, your where clause would be:
WHERE cart_id = 389 and user_id = 26
but given how trivial that is, it’s difficult to believe that’s really what you’ve been asking all along.
===
Updated based on latest example…
WHERE (cart_id = 389 and user_id = 26)
OR (cart_id is null and user_id = 26)

Order grouped table by id user sql

I want to order a grouped statement using as reference the number choosen by an specific user.
SELECT *
FROM likes
WHERE /**/
GROUP BY type
TABLE
id_user type
1420 1
1421 3
1422 3
1424 7
1425 4
1426 2
1427 1
expected result (at the end what user 1425 choosed)
1
2
3
7
4 //choosen by id_user 1425
I want to put the last row with the number choosed by the user. i just cant figure that out
You can aggregate and use a conditional max for ordering, like so:
select type
from likes
group by likes
order by max(case when id_user = 1425 then 1 else 0 end), type
If any row for the given type has an id_user that matches the chosen value, the conditional max returns 1, wich puts it last in the resultset. The second ordering criteria break the ties for groups that do not fulfill the condition.
If you are running MySQL, you can simplify the order by clause a little:
order by max(id_user = 1425), type

Count Instances Of Occuring String With Unique IDs

I need to count the number of times that a specific string occurs but they when one ID has the same string more than once, only count it once. Basically, I need to count the number of occurrences of a string that occur uniquely to an ID. I believe this should be a simple thing to do but I don't know what I'm doing. Here is my current code:
SELECT
RXNAME as Name,
DUPERSID as ID,
COUNT(RXNAME) as Number
FROM
`OmniHealth.PrescriptionsMEPS`
GROUP BY
ID,
Name
ORDER BY
Number
When run, it says everything was counted as 1. Thanks for the help!
UPDATE:
Dataset: https://storage.googleapis.com/omnihealth/MepsPrescriptionData.csv
OUTPUT when run with code above:
Row Name ID Number
1 SUMATRIPTAN 68896102 1
2 IBUPROFEN 65063102 1
3 PENICILLN VK 66179101 1
4 FUROSEMIDE 63217102 1
5 HYSINGLA ER 70373101 1
6 FUROSEMIDE 76090101 1
7 SKELETAL MUSCLE RELAXANTS 78414101 1
8 AMOXICILLIN 69467103 1
9 TRAMADOL HCL 67667101 1
10 PANTOPRAZOLE 60737102 1
11 CARBAMIDE PEROXIDE 6.5% OTIC SOLN 63990104 1
12 PROMETH/COD 68433101 1
13 AZITHROMYCIN 79045102 1
14 METRONIDAZOL 75414101 1
15 DEXILANT 69625101 1
16 TRAMADOL HCL 66890203 1
17 AZITHROMYCIN 73838101 1
18 COLCRYS 63856102 1
19 PERMETHRIN 62103107 1
20 ACETAMINOPHEN TAB 500 MG 62456102 1
not sure if it is what you asked - but if you are looking for DISTINCT COUNT - go with below:
#standardSQL
SELECT
RXNAME AS Name,
COUNT(DISTINCT DUPERSID) AS Number
FROM `OmniHealth.PrescriptionsMEPS`
GROUP BY 1
ORDER BY Number DESC
Try this...You are grouping on a different field than you are counting. I think you are meaning to group by RXNAME.
SELECT
RXNAME as Name,
DUPERSID as ID,
COUNT(RXNAME) as Number
FROM
`OmniHealth.PrescriptionsMEPS`
GROUP BY
ID,
RXNAME
ORDER BY
Number
I think you want:
SELECT DUPERSID as ID, COUNT(DISTINCT RXNAME) as Number
FROM `OmniHealth.PrescriptionsMEPS`
GROUP BY ID
ORDER BY Number;
This assumes that "same string" means "same value for RXNAME".

SQL : Check if result = number for each id

I have this sort of structure
ID STATUS
1 FIRSTSTAT
2 FIRSTSTAT
3 FIRSTSTAT
1 SECSTAT
3 SECSTAT
3 THIRDSTAT
3 FOURTHSTAT
3 FIFTHSTAT
I want to get the 3 back because he has all following status (FIRSTSTAT, SECSTAT, THIRDSTAT). Do you have an idea how I could make that?
It should be done by explicitely giving the statuses because other statuses exist so SELECT FROM WHERE = 'THIRDSTAT' is not ok since it should have all three statuses, not only one of them.
So I guess it should be done calculating the SUM or something like that.
I tried the following but of course, it does not work :
SELECT
FROM
WHERE
AND
AND
If the number of different status values is known to always be 3:
select id
from tablename
where status in ('FIRSTSTAT', 'SECSTAT', 'THIRDSTAT')
group by id
having count(distinct status) = 3

how to select one tuple in rows based on variable field value

I'm quite new into SQL and I'd like to make a SELECT statement to retrieve only the first row of a set base on a column value. I'll try to make it clearer with a table example.
Here is my table data :
chip_id | sample_id
-------------------
1 | 45
1 | 55
1 | 5986
2 | 453
2 | 12
3 | 4567
3 | 9
I'd like to have a SELECT statement that fetch the first line with chip_id=1,2,3
Like this :
chip_id | sample_id
-------------------
1 | 45 or 55 or whatever
2 | 12 or 453 ...
3 | 9 or ...
How can I do this?
Thanks
i'd probably:
set a variable =0
order your table by chip_id
read the table in row by row
if table[row]>variable, store the table[row] in a result array,increment variable
loop till done
return your result array
though depending on your DB,query and versions you'll probably get unpredictable/unreliable returns.
You can get one value using row_number():
select chip_id, sample_id
from (select chip_id, sample_id,
row_number() over (partition by chip_id order by rand()) as seqnum
) t
where seqnum = 1
This returns a random value. In SQL, tables are inherently unordered, so there is no concept of "first". You need an auto incrementing id or creation date or some way of defining "first" to get the "first".
If you have such a column, then replace rand() with the column.
Provided I understood your output, if you are using PostGreSQL 9, you can use this:
SELECT chip_id ,
string_agg(sample_id, ' or ')
FROM your_table
GROUP BY chip_id
You need to group your data with a GROUP BY query.
When you group, generally you want the max, the min, or some other values to represent your group. You can do sums, count, all kind of group operations.
For your example, you don't seem to want a specific group operation, so the query could be as simple as this one :
SELECT chip_id, MAX(sample_id)
FROM table
GROUP BY chip_id
This way you are retrieving the maximum sample_id for each of the chip_id.