I have 3 tables, which every table has it's own foreign key and primary key.
Table scheme looks like this :
tbl_cake
/---------------------------------------------------------------------------\
| CakeId (Primary key) | CakeName | UserId (Foreign Key from tbl_user) |
|----------------------------------------------------------------------------|
| 1 | BlackForest | 12345 |
|----------------------------------------------------------------------------|
| 2 | Fruit Pie | 98475 |
|----------------------------------------------------------------------------|
| 3 | Birthday Cake | 12345 |
|----------------------------------------------------------------------------|
| 4 | Raspberry Pie | 28475 |
\----------------------------------------------------------------------------/
tbl_user
/--------------------------------------\
| UserId (Primary key) | UserName |
|--------------------------------------|
| 12345 | Angelia |
|--------------------------------------|
| 98475 | Rudi |
|--------------------------------------|
| 56782 | Andika |
\--------------------------------------/
tbl_transaction
/--------------------------------------------------------------------------------------------------\
| TransactionId(Primary) | CakeId(Foreign) | UserId| Qty | Date | OrderType |
|--------------------------------------------------------------------------------------------------|
| 1 | 1 | 12345 | 1000 | 2020-04-01 10:05:01 | Drive Thru |
|--------------------------------------------------------------------------------------------------|
| 2 | 2 | 98475 | 200 | 2020-04-03 09:15:01 | On The Spot |
|--------------------------------------------------------------------------------------------------|
| 3 | 2 | 98475 | 500 | 2020-04-03 11:05:01 | On The Spot |
|--------------------------------------------------------------------------------------------------|
| 4 | 1 | 12345 | 150 | 2020-04-05 08:05:01 | On The Spot |
\--------------------------------------------------------------------------------------------------/
So the goals are :
Show UserId,TransactionId,Qty,Date and OrderType which :
Show all UserId, either it has any order or not.
If multiple order occurs, then show the latest data
If UserId don't have any order, fill the missing values with null
Finally, show the data with OrderType 'On The Spot'.
The expected result will be :
FINAL RESULT
/----------------------------------------------------------------------------------\
| UserId | TransactionId | Qty | Date | OrderType |
|----------------------------------------------------------------------------------|
| 12345 | 4 | 150 | 2020-04-05 08:05:01 | On The Spot|
|----------------------------------------------------------------------------------|
| 98475 | 3 | 500 | 2020-04-03 11:05:01 | On The Spot|
|----------------------------------------------------------------------------------|
| 56782 | null | null | null | null |
\----------------------------------------------------------------------------------/
I think using join(s) will accomplish this, but i'm not sure how, especially when determine if UserId has any order or not, and pick the latest order to be shown.
Many thanks!
In MySQL 8+, we would use ROW_NUMBER here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY Date DESC) rn
FROM tbl_transaction
WHERE OrderType = 'On The Spot'
)
SELECT
u.UserId,
t.TransactionId,
t.Qty,
t.Date,
t.OrderType
FROM tbl_user u
LEFT JOIN cte t
ON u.UserId = t.UserId AND rn = 1;
Demo
I managed to solve it (using left join and max function) :
select tbl_user.UserId,tbl_transaction.TransactionId,tbl_transaction.Qty,tbl_transaction.Date,
tbl_transaction.OrderType
from tbl_cake
left join tbl_user on tbl_user.UserId=tbl_cake.UserId
left join tbl_transaction on tbl_user.UserId=tbl_transaction.UserId
and
tbl_transaction.Date=(select max(Date) from tbl_transaction where UserId=tbl_User.UserId
and tbl_transaction.OrderType="On The Spot")
group by UserId
Related
I have some table like this
table request_buys
| id | invoice | user_id |
| -- | ----------------- | ------- |
| 3 | 20220405/01104298 | 1 |
table traces
| id | request_buy_id | status_id | created_at |
| -- | -------------- | --------- | ------------------- |
| 37 | 3 | 1 | 2022-03-27 14:12:25 |
| 38 | 3 | 2 | 2022-03-28 14:12:25 |
| 39 | 3 | 3 | 2022-03-29 14:12:25 |
| 40 | 3 | 4 | 2022-03-30 14:12:25 |
| 41 | 3 | 5 | 2022-03-31 14:12:25 |
| 42 | 3 | 6 | 2022-04-01 14:12:25 |
table statuses
| id | nama |
| -- | ----------------- |
| 1 | Order Placed |
| 2 | Order Paid |
| 3 | Accepted |
| 4 | Picked by Courier |
| 5 | In Transit |
| 6 | Delivered |
| 7 | Rated |
| 8 | Rejected |
| 9 | Canceled |
and then i try to design query like below
select
request_buys.invoice,
MAX(traces.id) as traces_id,
MAX(statuses.nama) as statuses_nama
from
`request_buys`
inner join `traces` on `request_buys`.`id` = `traces`.`request_buy_id`
inner join `statuses` on `traces`.`status_id` = `statuses`.`id`
where
`user_id` = 1
group by
request_buys.id
and produces output like the following
output
| invoice | traces_id | statuses_nama |
| ----------------- | --------- | ----------------- |
| 20220405/01104298 | 42 | Picked by Courier |
and the output i expect should be like in the table below
expect
| invoice | traces_id | statuses_nama |
| ----------------- | --------- | ----------------- |
| 20220405/01104298 | 42 | Delivered |
I understand my error is in MAX(statuses.nama) which I should change like removing MAX() in statuses.nama
But i just get error like this "SELECT list is not in GROUP BY clause and contains nonaggregated ... this is incompatible with sql_mode=only_full_group_by"
then I tried some to clear the value "ONLY_FULL_GROUP_BY" with a query like the following
SET sql_mode=(SELECT REPLACE(##sql_mode,'ONLY_FULL_GROUP_BY',''))
and the result is like this
output
| invoice | traces_id | statuses_nama |
| ----------------- | --------- | ----------------- |
| 20220405/01104298 | 42 | Order Placed |
and I'm really stuck at this
and how to make trace_id.status_id from the "GROUP BY" result based on request_buys.id still have a relationship with statuses.id
Your problem lies with your misuse of the MAX(statuses.nama) expression. Based on your expected output,you intend to get the statuses.nama which matches the MAX(traces.id), NOT the MAX(statuses.nama) value which returns the highest value in terms of alphabetic order. In this case, the initial letter 'P' > 'D' . I have tweaked your code a bit and tried it on workbench,supposing there are more than one invoice for a particular user.(e.g insert into request_buys values (4,'20230405/01104298',1); insert into traces values (43,4,7,'2022-04-01 14:12:25');) It works as intended.
select invoice, t.id as traces_id, s.nama as statuses_name from request_buys r
join traces t on r.id=t.request_buy_id
join statuses s on t.status_id=s.id
join
(select traces.request_buy_id, MAX(traces.id) as traces_id
from `request_buys`
inner join `traces` on `request_buys`.`id` = `traces`.`request_buy_id`
where
`user_id` = 1
group by
traces.request_buy_id ) join_t
on t.request_buy_id=join_t.request_buy_id and t.id=join_t.traces_id
;
If I'm understanding correctly, you're trying to retrieve the most recent status for each invoice. Using MAX(nama) won't return that result, because it just picks the maximum status name alphabetically.
Assuming you're using MySQL 8.x, use ROW_NUMBER() to sort and rank the statuses for each invoice, by the most recent date first. Then grab the latest one using where rowNum = 1
WITH cte AS (
SELECT rb.id AS request_buy_id
, rb.invoice
, t.id AS traces_id
, s.nama AS statuses_nama
, ROW_NUMBER() OVER(PARTITION BY rb.id ORDER BY t.created_at DESC) AS RowNum
FROM request_buys rb
INNER JOIN traces t ON rb.id = t.request_buy_id
INNER JOIN statuses s ON t.status_id = s.id
WHERE user_id = 1
)
SELECT *
FROM cte
WHERE RowNum = 1
;
Result:
request_buy_id
invoice
traces_id
statuses_nama
RowNum
3
20220405/01104298
42
Delivered
1
db<>fiddle here
I'm trying to select orders, which are send at least two times with the same addressId to a customer.
This is my table structure:
Customer Table:
+------------+-----------+
| customerId | addressId |
+------------+-----------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
+------------+-----------+
Relation for Addresses to Orders
+---------+-----------+
| orderId | addressId |
+---------+-----------+
| 1 | 1 |
| 2 | 2 |
| 3 | 2 |
| 4 | 3 |
| 5 | 4 |
| 6 | 4 |
+---------+-----------+
Order Table
+----+------------+-------+
| id | orderEntry | total |
+----+------------+-------+
| 1 | timestamp | 4711 |
| 2 | timestamp | 0815 |
| 3 | timestamp | 1337 |
+----+------------+-------+
Now I want a output like this:
+------------+---------+-----------+
| customerId | orderId | addressId |
+------------+---------+-----------+
| 2 | 2 | 2 |
| 2 | 3 | 2 |
| 4 | 5 | 4 |
| 4 | 6 | 4 |
+------------+---------+-----------+
I've tried to get the right result with these Query, but I think I can't count the addresses this way.
SELECT C.`customerId`, AO.`orderId`, AO`addressId`
FROM customer AS C
JOIN address_order AS AO ON AO.addressId = C.addressId
JOIN order AS O ON O.id = AO.orderId
GROUP BY AO.`orderId`
HAVING (COUNT(AO.`addressId`) > 1);
With these Query I only get a result like this:
+------------+---------+-----------+
| customerId | orderId | addressId |
+------------+---------+-----------+
| 2 | 2 | 2 |
| 4 | 5 | 4 |
+------------+---------+-----------+
I don't see the usage of order table here. However you can use the order table into the consideration if you want to make sure that the order table data and address_order should have data. You can write the query as
select
c.customerId,
ao.orderId,
ao.addressId
from customer c
join address_order ao on ao.addressId = c.addressId
join (
select addressId, count(*) as tot from address_order
group by addressId having tot = 2
)x on x.addressId = ao.addressId
If you want to make sure all the orderId from customer_order are in the order table then you can add another join at the end as
join `order` o on o.id = ao.orderId
Try this
SELECT customerId FROM customer INNER JOIN (SELECT * FROM address_order GROUP BY addressId
HAVING (COUNT(addressId) > 1)) AS t1 ON customer.addressId=t1.addressId
I am trying to create a query with a GROUP_CONCAT added as a new column in my current query, first here are my tables:
Users table
+----+----------+--------------+
| id | username | date_created |
+----+----------+--------------+
| 1 | user1 | 2000-03-16 |
| 2 | user2 | 2001-05-14 |
| 3 | user3 | 2002-01-13 |
| 4 | user4 | 2003-03-14 |
+----+----------+--------------+
Shifts table
+----+------------+--------------+
| id | shift_name | date_created |
+----+------------+--------------+
| 1 | shift1 | 2002-05-10 |
| 2 | shift2 | 2002-07-11 |
| 3 | shift3 | 2002-09-23 |
+----+------------+--------------+
Accounts table
+----+--------------+--------------+
| id | account_name | date_created |
+----+--------------+--------------+
| 1 | account1 | 2001-05-01 |
| 2 | account2 | 2001-05-02 |
| 3 | account3 | 2001-05-03 |
+----+--------------+--------------+
Shift Mapping table
+----+---------+----------+------------+
| id | user_id | shift_id | account_id |
+----+---------+----------+------------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 2 | 2 |
| 3 | 3 | 1 | 1 |
+----+---------+----------+------------+
basically, I want a query that gets all the user (to display in a table) with a custom column that shows all shift that is attach to that user(if there is no shift attach to that obviously has a null result)
Here is the query I've done so far:
SELECT users.id AS user_id, users.username, users.date_created,
GROUP_CONCAT(DISTINCT (t.shift_name)) AS shifts
FROM (`users`)
LEFT JOIN
(SELECT s.shift_name, sm.user_id FROM shift_map sm
LEFT JOIN shifts s ON sm.shift_id = s.id) t
ON users.id = t.user_id
GROUP BY user_id
ORDER BY `users`.`date_created` DESC;
Now there is no problem getting the users with a shift attach to it, my problem is that the users with no shifts attach to only returns 1 result which is caused by the GROUP BY user_id how can I exclude the users with no shift in the GROUP BY or how can I return all the users with attached shifts and with no attach shifts? Thanks.
Update
Here is the example result I want to see:
+---------+----------+--------------+----------------+
| user_id | username | date_created | shifts |
+---------+----------+--------------+----------------+
| 1 | user1 | 2000-03-16 | shift1,shift2 |
| 2 | user2 | 2001-05-14 | (NULL) |
| 3 | user3 | 2002-01-13 | shift1 |
| 4 | user4 | 2003-03-14 | (NULL) |
+---------+----------+--------------+----------------+
My problem in my query is that it only shows only 1 user with null shifts.
SELECT users.id AS user_id, users.username, users.date_created,
GROUP_CONCAT(DISTINCT (t.shift_name)) AS shifts
FROM (`users`)
LEFT JOIN
(SELECT s.shift_name, sm.user_id FROM mapping sm
LEFT JOIN shifts s ON sm.shift_id = s.id) t
ON users.id = t.user_id
GROUP BY username
ORDER BY user_id
+---------+----------+--------------+---------------+
| user_id | username | date_created | shifts |
+---------+----------+--------------+---------------+
| 1 | user1 | 2000-03-16 | shift1,shift2 |
| 2 | user2 | 2001-03-16 | NULL |
| 3 | user3 | 2002-03-16 | shift1 |
| 4 | user4 | 2003-03-16 | NULL |
+---------+----------+--------------+---------------+
My Bad, I can just use the simple LEFT JOIN:
SELECT users.id AS user_id, users.username, users.date_created,
GROUP_CONCAT(DISTINCT (shift.shift_name)) AS shifts
FROM (`users`)
LEFT JOIN shifts_map ON users.id = shifts_map.user_id
LEFT JOIN shifts ON shifts_map.shift_id = shift.id
GROUP BY user_id
ORDER BY `users`.`date_created` DESC;
I am just complicating the query, Forgot that the simple LEFT JOIN can do the trick. Thanks.
I have two tables as below. The Id column value in both the tables mentioned below is auto-incremented.
Group
+----+-----------+----------------+
| Id | GroupId | GroupName |
+----+-----------+----------------+
| 1 | 10 | Grp1#abc.com |
| 2 | 20 | Grp2#abc.com |
| 3 | 30 | Grp3#xyz.com |
| 4 | 40 | Grp4#def.com |
+----+-----------+----------------+
Customer
+---+-----------------+------------+----------+---------------+
| Id | GroupAliasName | Domain | GroupId | CustomerName |
+---+-----------------+------------+----------+---------------+
| 1 | Grp1 | abc.com | null | Cust1 |
| 2 | Grp2 | abc.com | null | Cust2 |
| 3 | Grp3 | xyz.com | null | Cust3 |
| 4 | Grp4 | def.com | null | Cust4 |
+---+-----------------+------------+----------+---------------+
Now from Customer table 'GroupAliasName' and 'Domain' when concatenated as 'GroupAliasName#Domain' is equivalent to 'GroupName' in Group table.
Using the concatenated value from Customer table, I need to pull the 'GroupId' from the Group table and populate the same in Customer table's 'GroupId' as below
Customer
+----+----------------+------------+----------+---------------+
| Id | GroupAliasName | Domain | GroupId | CustomerName |
+----+----------------+-----------+---------+-----------------+
| 1 | Grp1 | abc.com | 10 | Cust1 |
| 2 | Grp2 | abc.com | 20 | Cust2 |
| 3 | Grp3 | xyz.com | 30 | Cust3 |
| 4 | Grp4 | def.com | 40 | Cust4 |
+----+----------------+------------+----------+---------------+
The query which I tried is as below
UPDATE Customer SET GroupId =
(SELECT GroupId FROM Group G
WHERE GroupName =
(SELECT CONCAT(GroupAliasName, '#', Domain) AS GroupName
FROM Customer
WHERE Domain IS NOT NULL) AND G.GroupName = GroupName);
But I get error as 'Subquery returns more than 1 row'.
Please suggest or provide your inputs.
Try this:
update customer as cust
inner join `group` grp on concat(cust.groupaliasname, '#', cust.domain) = grp.groupname
set cust.groupId = grp.groupId;
Try with somethings like this
UPDATE Customer as c
INNER JOIN Group as g on ( CONCAT(c.GroupAliasName, '#', c.Domain) = g.GroupName)
SET c.GroupId = g.GroupId;
I need to get emtpy fields where data is repeated
For example an customer can have two or more contact persons, so query return (just shorted qyery resul):
CUSTOMER_NAME| CONTACT_PERSON|ETC..
dell | Ighor |etc..
dell | Dima |etc..
but I'm need :
CUSTOMER_NAME| CONTACT_PERSON|etc...
dell | Ighor |etc..
NULL | Dima |etc..
SELECT
`contact`.*,
`branch_has_equipment`.*,
`branch_has_contact`.*,
`equipment`.*,
`customer_has_branch`.*,
`branch`.*,
`customer`.*,
`ip`.*
FROM `customer`
INNER JOIN `customer_has_branch`
ON `customer`.`customer_id` = `customer_has_branch`.`customer_id`
INNER JOIN `branch`
ON `customer_has_branch`.`branch_id` = `branch`.`branch_id`
INNER JOIN `branch_has_equipment`
ON `branch`.`branch_id` = `branch_has_equipment`.`branch_id`
INNER JOIN `equipment`
ON `branch_has_equipment`.`equipment_id` = `equipment`.`equipment_id`
INNER JOIN `branch_has_contact`
ON `branch`.`branch_id` = `branch_has_contact`.`branch_id`
INNER JOIN `contact`
ON `branch_has_contact`.`contact_id` = `contact`.`contact_id`
INNER JOIN `equipment_has_ip`
ON `equipment`.`equipment_id` = `equipment_has_ip`.`equipment_id`
INNER JOIN `ip`
ON `equipment_has_ip`.`equipment_id` = `ip`.`ip_id`
WHERE `customer`.`inservice` = 'Yes'
ORDER BY `customer`.`customer_name`
in additional, tables ^
Customer
customer_id
customer_name
inservice
service_type
comment
Branch
branch_id
city
address
Equipment
equipment_id
brand
model
connection_param
connection_type
serial_number
id
release
Contact
contact_id
name
surname
phone_mobile
phone_work
phone_other
position
customer_has_branch_id
customer_id
branch_id
Since I have no idea how any of those tables relate to one another, my only answer to you is to use an OUTER JOIN, which will keep NULL results.
I'm not seriously advocating this solution because really i think this sort of thing should be handled in application level code (e.g. a bit of PHP), but anyway, consider the following:
SELECT * FROM my_table;
+------+--------+--------+
| game | points | player |
+------+--------+--------+
| 1 | 5 | Adam |
| 1 | 8 | Alan |
| 1 | 7 | Brian |
| 1 | 6 | John |
| 2 | 2 | Adam |
| 2 | 3 | Alan |
| 2 | 4 | Brian |
| 2 | 6 | John |
+------+--------+--------+
SELECT IF(game= #prev,'',game)
, #prev := game
FROM my_table ORDER BY game,player;
+-------------------------+---------------+
| IF(game= #prev,'',game) | #prev := game |
+-------------------------+---------------+
| 1 | 1 |
| | 1 |
| | 1 |
| | 1 |
| 2 | 2 |
| | 2 |
| | 2 |
| | 2 |
+-------------------------+---------------+