I'm trying to get the correct records but for reason I've some issue in Having clause I guess, can anyone please help me out?
CASE 1:
Trying to select rows where order_id = 1 (New Order) but should not have more than 1 record with the same order id
CASE 2:
Select rows where order_id = 2 (Printed Order) but should also select new orders too and apply CASE 1, in other words Query should select where order_id=2 OR where order_id=1 if( order_id = 1 then should not have more than 1 record with the same order id)
I've a table where:
order_id = id of the order
status_id = different status id e.g 1 = New, 2 = Printed, 3 = Processing etc...
status_change_by = id of the admin who change the order status from new to printed to processing...
order_id | status_id | status_change_by
1 | 1 | (NULL)
1 | 2 | 12
1 | 3 | 12
2 | 1 | (NULL)
3 | 1 | (NULL)
4 | 1 | (NULL)
1 | 4 | 13
5 | 1 | (NULL)
3 | 2 | (NULL)
Here's my simple mySQL query:
SELECT * from order_tracking
where status_id = 1
group by order_id
having count(order_id) <= 2;
I even created SQL fiddle for the reference, please check if I'm doing wrong or I need complex query with CASE or IF statements?
http://sqlfiddle.com/#!2/16936/3
If this link doesn't work, please create one by this code:
CREATE TABLE order_tracking
(
track_id int auto_increment primary key,
order_id int (50),
status_id int(20),
status_changed_by varchar(30)
);
Here's the insertion:
INSERT INTO order_tracking
(order_id, status_id, status_changed_by)
VALUES
(1,1,''),
(1,2,12),
(1,3,12),
(2,1,''),
(3,1,''),
(4,1,''),
(1,4,13),
(5,1,''),
(3,2,'');
Your earliest response should be appreciated!
Thanks for the time.
Desire result:
Case:1 which is quite simple where result should be something like that: Only New orders with no more than 1 record
Order_id | status_id | status_changed_by
2 | 1 | (NULL)
4 | 1 | (NULL)
3 | 1 | (NULL)
Case 2 result:
Order_id | status_id | status_changed_by
1 | 4(max id)| (NULL)
2 | 1 | (NULL)
4 | 1 | (NULL)
3 | 2(max id)| (NULL)
It seems, by reading between the lines of your question, that you want to display the highest numerical value of status for each order id. That is, it seems that your orders progress from status 1 to 2 to 3 and so forth.
Here's how you do that. First, you determine which is the highest status for each order, as follows:
SELECT MAX(status_id) AS status_id,
order_id
FROM order_tracking
GROUP BY order_id
This query gives you one row for each order_id showing the maximum value of the status id.
Then, you use it as a subquery and join to your original table like so. http://sqlfiddle.com/#!2/16936/11/0
SELECT o.order_id, o.status_id, o.status_changed_by
FROM order_tracking AS o
JOIN (
SELECT MAX(status_id) AS status_id,
order_id
FROM order_tracking
GROUP BY order_id
) AS m ON o.order_id = m.order_id AND o.status_id = m.status_id
ORDER BY o.order_id
This will give you a nice result with the highest status for each order.
| ORDER_ID | STATUS_ID | STATUS_CHANGED_BY |
|----------|-----------|-------------------|
| 1 | 4 | 13 |
| 2 | 1 | |
| 3 | 2 | |
| 4 | 1 | |
| 5 | 1 | |
Please note: If you were to put an autoincrementing ID column into your order_tracking table, things might work better for you. You'd be able to get the most recently INSERTed status for each order_id rather than the numerically highest status. This would be a very helpful change to your table layout, in my opinion. You'd do that like this:
SELECT o.order_id, o.status_id, o.status_changed_by
FROM order_tracking AS o
JOIN (
SELECT MAX(id) AS id,
order_id
FROM order_tracking
GROUP BY order_id
) AS m ON o.id = m.id
ORDER BY o.order_id
Related
I have written a query to get the items from the table which doesn't have any child items. It's working fine but is very slow.
Any better/easier/optimized way to write the same thing?
select distinct id, (select count(i.item_id) from order_item as i where i.parent_item_id = o.item_id) as c
from order_item as o
where product_type = 'bundle'
having c = 0
order by id desc
limit 10;
Few of the fields are these to get the idea of a structure
Table: order_item
Columns:
item_id PK
order_id
parent_item_id
product_id
product_type
item_id | order_id | parent_item_id | product_id | product_type
-----------------------------------------------------------------
1 | 1 | null | 1 | bundle
2 | 1 | 1 | 2 | simple
3 | 1 | 1 | 3 | simple
4 | 1 | null | 4 | bundle
5 | 2 | null | 1 | bundle
6 | 2 | 5 | 2 | simple
7 | 2 | 5 | 3 | simple
Query should only return the 4rth item
Try below. Also consider creating indexes on PARENT_ITEM_ID and ITEM_ID
SELECT OI.*
FROM ORDER_ITEM OI
LEFT JOIN ORDER_ITEM OI2
ON OI2.PARENT_ITEM_ID = OI.ITEM_ID
WHERE OI.PRODUCT_TYPE = 'bundle' AND OI2.PARENT_ITEM_ID IS NULL
I would suggest not exists:
select oi.*
from order_item oi
where oi.product_type = 'bundle' and
not exists (select 1
from order_item oi2
where oi2.parent_item_id = oi.item_id and oi2.product_type = 'bundle'
)
order by id desc
limit 10;
For performance, you want an index on order_item(parent_item_id, product_type).
Note: I'm not sure you want the product_type filter in the subquery, but it is the logic your query is using.
I have the following columns:
| order_id | client_id | order_timestamp | buyer_id | (all INTs)
It started with the easy-sounding task "Show me the buyer of the last order for each client", so basically
SELECT
client_id,
max(order_timestamp),
buyer_id
FROM table t
GROUP BY client_id;
if GROUP BY would work as one would expect/wish. I know that this is kind of a common problem, but I've never seen this case in particular where you need another value in addition to the one you're grouping by. I guess using the Window functions could help, but we're using MariaDB 10.0, so that's not really an option. I tried different subselect and joins but it always ends with the problem that I can't use the order_id to join, since I have to group by the client_id. It also came to my mind to join using the client_id AND order_timestamp but the combination is not unique in the table, since it's possible to have orders with the exact same (Unix) timestamp for one client or client/buyer combination (so yeah, this would be an edge case, I would need the buyer of the order with the higher order_id, but that's a problem for another day I guess).
If the table was filled like
| order_id | client_id | order_timestamp | buyer_id |
| 1 | 123 | 9876543 | 2 |
| 2 | 123 | 9876654 | 3 |
| 3 | 234 | 9945634 | 2 |
| 4 | 234 | 9735534 | 1 |
I would like to get
| client_id | buyer_id |
------------|----------|
| 123 | 3 |
| 234 | 2 |
Hopefully, somebody can help me, so I can go to sleep in peace tonight.
If your MariaDB version supports window functions you can use ROW_NUMBER():
select t.client_id, t.buyer_id
from (
select *,
row_number() over (partition by client_id order by order_timestamp desc, order_id desc) rn
from tablename
) t
where t.rn = 1
See the demo.
Results:
| client_id | buyer_id |
| --------- | -------- |
| 123 | 3 |
| 234 | 2 |
Without window functions use NOT EXISTS:
select t.client_id, t.buyer_id
from tablename t
where not exists (
select 1 from tablename
where client_id = t.client_id
and (
order_timestamp > t.order_timestamp
or (order_timestamp = t.order_timestamp and order_id > t.order_id)
)
)
If you use max(field), it will pickup the first column of the group condition. In your case first occuring client_id per group which is not what you want.
Try this.
select client_id, order_timestamp, buyer_id from t
where order_timestamp=
(select max(ot) from t as tcopy where tcopy.client_id= t.client_id )
group by client_id;
I'm trying to update the value of a column based on duplicates in my database, but I'm struggling to find the correct query.
Here's my db structure:
id | product_id | order_id | parent_id
--------------------------------------
1 1 1 SMITH1
2 1 2 SMITH1
3 2 3 BLOGGS1
4 2 4 BLOGGS1
I want to update the order_id to be the same, where we have duplicates of both product_id AND parent_id.
Currently I've found the duplicates like so:
SELECT
*,
COUNT(parent_id),
COUNT(product_id)
FROM
mytable
GROUP BY parent_id, product_id
HAVING COUNT(parent_id) > 1
AND COUNT(product_id) > 1
But I'm now struggling with the update/join to set the order_id values the same (can be minimum order_id value preferably).
Any help appreciated!
With a join of the table to the minimum value of order_id for each combination of product_id and parent_id:
update mytable t inner join (
select product_id, parent_id, min(order_id) order_id
from mytable
group by product_id, parent_id
having min(order_id) <> max(order_id)
) tt on tt.product_id = t.product_id and tt.parent_id = t.parent_id
set t.order_id = tt.order_id;
This code will prevent any unnecessary updates in case there is only one order_id for that product_id and parent_id.
See the demo.
Results:
| id | product_id | order_id | parent_id |
| --- | ---------- | -------- | --------- |
| 1 | 1 | 1 | SMITH1 |
| 2 | 1 | 1 | SMITH1 |
| 3 | 2 | 3 | BLOGGS1 |
| 4 | 2 | 3 | BLOGGS1 |
I have the following table:
+---------+--------------+----------+
| item_id | location_id | price |
+---------+--------------+----------+
| 1 | 1 | 100 |
| 1 | 1 | 250 |
| 1 | 2 | 50 |
| 2 | 1 | 250 |
| 2 | 1 | 1000 |
| 3 | 1 | 1000 |
| 3 | 2 | 100 |
+---------+--------------+----------+
I can reduce this down to the minimum values using this query
SELECT
item_id, location_id, MIN(price) AS Price
from
table
GROUP BY item_id , location_id
This gets me
+---------+--------------+----------+
| item_id | location_id | price |
+---------+--------------+----------+
| 1 | 1 | 100 |
| 1 | 2 | 50 |
| 2 | 1 | 250 |
| 3 | 1 | 1000 |
| 3 | 2 | 100 |
+---------+--------------+----------+
I want to reduce this further. I am using the rows with a location_id of 1 as a reference row. For each row that has an item_id matching the reference row's item_id but a different location id. I want to compare that row's price with the reference row's price. If the price is lower than the reference row's price, I want to filter that row out.
My final result should include the reference row for each item id and any rows that met the criteria of the price being lower than the reference row price.
I have a hunch that I can use the HAVING clause to do this but I am having trouble compiling the statement. How should I construct the HAVING statement?
Thanks in advance
Nah, having can't help you like this, having is for things like you need filter min() result for something
e.g:
select id,min(price) from table where date = '2016-3-18' group by id having min(price) = 50
it will show you the records that min(price)=50
let's back to your case, there are lots of way to do that,
1. left join
select a.item_id,a.location_id,a.price
from table a
left join table b
on a.location_id = b.location_id and a.price > b.price
where b.price is null
2. exists
select a.item_id,a.location_id,a.price
from table a
where exists(
select 1 from
(select location_id,min(price)as price from table group by location_id)b
where a.location_id = b.location_id and a.price = b.price
)
normally i ll recommand you use exists
Hi I have a table that looks like
-----------------------------------------------------------
| id | group_id | source_id | target_id | sortsequence |
-----------------------------------------------------------
| 2 | 1 | 2 | 4 | 1 |
-----------------------------------------------------------
| 4 | 1 | 20 | 2 | 1 |
-----------------------------------------------------------
| 5 | 1 | 2 | 14 | 1 |
-----------------------------------------------------------
| 7 | 1 | 2 | 7 | 3 |
-----------------------------------------------------------
| 20 | 2 | 20 | 4 | 3 |
-----------------------------------------------------------
| 21 | 2 | 20 | 4 | 1 |
-----------------------------------------------------------
Scenario
There are two scenarios that needs to be handled.
Sortsequence column value should be unique against one source_id and group_id. For example if all the records having group_id = 1 AND source_id = 2 should have sortsequence unique. In above example records having id= and 5 which are having group_id = 1 and source_id = 2 have same sortsequence which is 1. This is faulty record. I need to find out these records.
If group_id and source_id is same. The sortsequence columns value should be continous. There should be no gap. For example in above table records having id = 20, 21 having same group_id and source_id and sortsequence value is 3 and 1. Even this is unique but there is a gap in sortsequence value. I need to also find out these records.
MY So Far Effort
I have written a query
SELECT source_id,`group_id`,GROUP_CONCAT(id) AS children
FROM
table
GROUP BY source_id,
sortsequence,
`group_id`
HAVING COUNT(*) > 1
This query only address the scenario 1. How to handle scenario 2? Is there any way to do it in same query or I have to write other to handle second scenario.
By the way query will be dealing with million of records in table so performance must be very good.
Got answer from Tere J Comments. Following query covers above mentioned both criteria.
SELECT
source_id, `group_id`, GROUP_CONCAT(id) AS faultyIDS
FROM
table
GROUP BY
source_id,group_id
HAVING
COUNT(DISTINCT sortsequence) <> COUNT(sortsequence) OR COUNT(sortsequence) <> MAX(sortsequence) OR MIN(sortsequence) <> 1
May be it can help others.
Try this query it will solve both of the cases as you have mentioned in the question.
SELECT
a.*
FROM
tbl a
INNER JOIN
(select
#rn:=IF(#prevG = group_id AND #prevS = source_id, #rn + 1, 1) As rId,
#prevG:=group_id AS group_id,
#prevS:=source_id AS source_id,
id,
sortsequence
FROM
tbl
join
(select #rn:=0, #prevS:=0, #prevG:=0)b
order by group_id, source_id, id) b
ON a.id = b.id AND a.SORTSEQUENCE <> b.RID;
FIDDLE