Joining a subquery using an outer column that uses a group function - sql

So this one should be pretty simple for most of you:
My table has an ID, an order_id and a status.
The same order_id may have several IDs.
What I need to do is get the last ID from each order_id, which is pretty simple:
SELECT order_id, max(ID) AS last_id
FROM mytable
GROUP BY order_id
Now, I also need to get the status that is linked to last ID, so what I was trying to do was:
SELECT order_id, max(ID) AS last_id, x.status
FROM mytable t
LEFT JOIN (SELECT ID, status
FROM mytable) x ON last_id = x.ID
I know I'm not allowed to use the last_id alias to join the subquery, as it says it does not exist. So how do I go about this?

You can't use the alias in the FROM or in the WHERE parts of the query, you should use max(t.ID):
SELECT order_id, max(t.ID) AS last_id, x.status
FROM mytable t
LEFT JOIN (SELECT ID, status
FROM mytable) x ON MAX(t.ID) = x.ID
You can also wrap the query as a subquery and then do the join using the alias:
SELECT t.order_id, t.last_id, x.status
FROM (
SELECT order_id, max(ID) AS last_id
FROM mytable
) t
LEFT JOIN mytable x
ON t.last_id = x.ID

An alternative is to DISTINCT ON the column order_id and then apply max() on id.
SELECT DISTINCT ON (order_id)
order_id, max(id) AS last_id,
status
FROM mytable
GROUP BY order_id,status;
Demo: db<>fiddle

Related

Select rows with a duplicate ID but different value in another column

I have a table like this
I would like to select the Itemid that occurs more than once with a different Rate with group by Masterid
The output should be something like:
You might try the following:
SELECT masterid, detailid, itemid, rate FROM mytable
WHERE (masterid, detailid, rate) IN
(
SELECT masterid, detailid, rate FROM mytable t
JOIN mytable o ON o.masterid = t.masterid
AND o.detailid = t.detailid AND o.rate <> t.rate
GROUP BY t.masterid, t.detailid, t.rate
HAVING COUNT(*) >= 2
)
The inner join within the sub-query assures only rows appearing that have an unequal counter part. Alternatively you might add another sub-query condition to the outer query:
AND EXISTS
(
SELECT * FROM mytable o
WHERE o.masterid = t.masterid AND o.detailid = t.detailid AND o.rate <> t.rate
)
I believe you are looking for a query like below
select t1.* from t t1
join
(
select masterid,itemid
from t
group by masterid,itemid
having count(distinct rate )>1
)t2
on t1.masterid=t2.masterid and t1.itemid=t2.itemid
order by masterid,detailid
and here's a working db fiddle
Try following code:
Select masterid, detailid, rate, count(*) as count from Mytable
group by masterid, detailid, rate
having count(*) > 1

SQL MAX funtion where not all atributes are in the group by

So my current problem is that I have two tables that look like this:
table1(name, num_patient, quant, inst)
table2(inst_name, num_region)
Where I want to find the patient with max quantity per region.
I first had the idea of doing something like this:
SELECT num_region, num_patient, MAX(quant)
FROM
(SELECT num_patient, quant, num_region
FROM table1
INNER JOIN table2
ON table1.inst = table2.inst_name) AS joined_tables
GROUP BY num_region;
But this doesn't work since either num_patient has to be on the GROUP BY (and this way it doesn't return the max value by region anymore) or I have to remove it from the SELECT (also doesn't work because I need the name of each patient). I have tried to fix my issue with a WHERE quant = MAX() statement but couldn't get it to work. Is there any workaround to this?
Use DISTINCT ON:
SELECT DISTINCT ON (num_region), num_patient, quant, num_region
FROM table1 t1 JOIN
table2 t2
ON t1.inst = t2.inst_name
ORDER BY num_region, quant DESC;
DISTINCT ON is a convenient Postgres extension. It returns one row per keys specified in the SELECT, based on the ordering in the ORDER BY.
Being an extension, not all databases support this functionality -- even databases derived from Postgres. The traditional method would use ROW_NUMBER():
SELECT t.*
FROM (SELECT num_patient, quant, num_region,
ROW_NUMBER() OVER (PARTITION BY num_region ORDER BY quant DESC) as seqnum
FROM table1 t1 JOIN
table2 t2
ON t1.inst = t2.inst_name
) t
WHERE seqnum = 1;
This is a duplicate of the DISTINCT ON question I linked.
SELECT distinct on (num_region) num_patient, quant, num_region
FROM table1
INNER JOIN table2
ON table1.inst = table2.inst_name
ORDER BY num_region, quant desc

Subqueries with different universes

I have an Oracle DB and I need to run a select with sub selects, however, none of them share the same table universe, therefore, I would need to do something like this:
SELECT (
SELECT COUNT(*)
FROM user_table
) AS tot_user,
(
SELECT COUNT(*)
FROM cat_table
) AS tot_cat,
(
SELECT COUNT(*)
FROM course_table
) AS tot_course
I know this is possible at other databases but I need something like this for Oracle.
Can someone help?
To make this work in oracle, add from dual to the end:
SELECT (SELECT COUNT(*)
FROM user_table
) AS tot_user,
(SELECT COUNT(*)
FROM cat_table
) AS tot_cat,
(SELECT COUNT(*)
FROM course_table
) AS tot_course
FROM dual;
A database independent way of writing the query is:
select tot_user, tot_cat, tot_course
from (SELECT COUNT(*) as tot_user
FROM user_table
) u cross join
(SELECT COUNT(*) as tot_cat
FROM cat_table
) c cross join
(SELECT COUNT(*) as tot_course
FROM course_table
) ct;

want to select same product_id but bigger id row

i have some problem about sql , i want to select the bigger warehouse_product_id and with same product_id row,i have try to use
please help
Table:
http://postimg.org/image/mkavxnmg9/
i want to:
http://postimg.org/image/8msomu47l/
SELECT warehouse_product_id FROM [your table] where product_id="value"
unless I missed what you're getting at, which is entirely possible
You seem to be looking for a greatest-n-per-group solution. For a given product_id and warehouse_id pair you need to get the max warehouse_product_id:
SELECT t1.* FROM aTable t1
JOIN (
SELECT product_id, warehouse_id, MAX(warehouse_product_id) maxVal
FROM aTable
GROUP BY product_id, warehouse_id
) t2
ON t1.product_id = t2.product_id AND t1.warehouse_id = t2.warehouse_id AND t1.warehouse_product_id = t2.maxVal
Alternatively:
SELECT t1.* FROM aTable t1
LEFT JOIN aTable t2
ON t1.product_id = t2.product_id AND t1.warehouse_id = t2.warehouse_id AND t1.warehouse_product_id < t2.warehouse_product_id
WHERE t2.warehouse_product_id IS NULL
These solutions should work on most DBMS.
I have assumed qty and enable have the same values for the same warehouse/product. If not, you'll need to join back to the table to get those.
select warehouse_id, max(warehouse_product_id) as item_id, product_id, max(qty), max(enable)
from warehouse_product
group by warehouse_id, product_id

SQL Select Distinct with Conditional

Table1 has columns (id, a, b, c, group). There are several rows that have the same group, but id is always unique. I would like to SELECT group,a,b FROM Table1 WHERE the group is distinct. However, I would like the returned data to be from the row with the greatest id for that group.
Thus, if we have the rows
(id=10, a=6, b=40, c=3, group=14)
(id=5, a=21, b=45, c=31, group=230)
(id=4, a=42, b=65, c=2, group=230)
I would like to return these 2 rows:
[group=14, a=6,b=40] and
[group=230, a=21,b=45] (because id=5 > id=4)
Is there a simple SELECT statement to do this?
Try:
select grp, a, b
from table1 where id in
(select max(id) from table1 group by grp)
You can do it using a self join or an inner-select. Here's inner select:
select `group`, a, b from Table1 AS T1
where id=(select max(id) from Table1 AS T2 where T1.`group` = T2.`group`)
And self-join method:
select T1.`group`, T2.a, T2.b from
(select max(id) as id,`group` from Table1 group by `group`) T1
join Table1 as T2 on T1.id=T2.id
2 selects, your inner select gets:
SELECT MAX(id) FROM YourTable GROUP BY [GROUP]
Your outer select joins to this table.
Think about it logically, the inner select gets a sub set of the data you need.
The outer select inner joins to this subset and can get further data.
SELECT [group], a, b FROM YourTable INNER JOIN
(SELECT MAX(id) FROM YourTable GROUP BY [GROUP]) t
ON t.id = YourTable.id
SELECT mi.*
FROM (
SELECT DISTINCT grouper
FROM mytable
) md
JOIN mytable mi
ON mi.id =
(
SELECT id
FROM mytable mo
WHERE mo.grouper = md.grouper
ORDER BY
id DESC
LIMIT 1
)
If your table is MyISAM or id is not a PRIMARY KEY, then make sure you have a composite index on (grouper, id).
If your table is InnoDB and id is a PRIMARY KEY, then a simple index on grouper will suffice (id, being a PRIMARY KEY, will be implictly included).
This will use an INDEX FOR GROUP-BY to build the list of distinct groupers, and for each grouper it will use the index access to find the maximal id.
Don't know how to do it in mysql. But the following code will work for MsSQL...
SELECT Y.* FROM
(
SELECT DISTINCT [group], MAX(id) ID
FROM Table1
GROUP BY [group]
) X
INNER JOIN Table1 Y ON X.ID=Table1.ID