MYSQL Complex Join one-to-many - mysql

I have the following tables:
clients:
| id | name | code | zone |
--------------------------------
| 1 | client 1 | a1b1 | zone1|
| 2 | client 2 | a2b2 | zone2|
contacts:
| id_contact | first_name | last_name |
----------------------------------------
| 11 | first1 | last1 |
| 22 | first2 | last2 |
| 33 | first3 | last3 |
| 44 | first4 | last4 |
client_contacts:
| id_client | id_contact |
--------------------------
| 1 | 11 |
| 1 | 22 |
| 1 | 33 |
| 2 | 11 |
| 2 | 44 |
offers:
| id_offer | id_client | value |
--------------------------
| 111 | 1 | 100 |
| 222 | 1 | 200 |
| 333 | 1 | 300 |
| 444 | 2 | 400 |
I would like through a optimal select to obtain:
| id_client | name | code | zone | contacts_pers | total_offer_value |
----------------------------------------------------------------------------
| 1 | client 1 | a1b1 | zone1 | first1 last1; | 600 |
first2 last2;
first3 last3;
| 2 | client 2 | a2b2 | zone2 | first1 last1; | 400 |
first4 last4;
I know how to get the desired result with "group_concat" and stored procedures for "total_offer_value". But how to get the desired result from a single efficient select?

SELECT c.id, c.name, c.code, c.zone, GROUP_CONCAT(DISTINCT CONCAT(co.first_name, " ", c.last_name) SEPARATOR ";") AS contact_pers, func_total_offer_value(c.id) AS total_offer_value
FROM clients c
LEFT OUTER JOIN (client_contacts cc, contacts co) ON ( c.id = cc.id_client AND cc.id_contact = co.id_contact )
GROUP BY c.id

Related

MySQL select users who was in range of dates

Hello :) I need to create sql which will calculate advances for user but only for that one who was in work. Tables looks like:
users:
| id | firstName | lastName |
| -- | --------- | -------- |
| 1 | John 1 | Test 1 |
| 2 | John 2 | Test 2 |
| 3 | John 3 | Test 3 |
| 4 | John 4 | Test 4 |
users_advances:
| id | user_id | amount | d_add | status_id |
| -- | ------- | ------ | ---------- | --------- |
| 1 | 1 | 100 | 2022-07-09 | 1 |
| 2 | 1 | 50 | 2022-07-10 | 2 |
| 3 | 2 | 100 | 2022-07-03 | 1 |
| 4 | 2 | 50 | 2022-07-05 | 2 |
| 5 | 2 | 100 | 2022-03-09 | 1 |
| 6 | 1 | 50 | 2022-07-02 | 2 |
users_arrivals
| id | user_id | start_date | end_date |
| -- | ------- | ---------- | ---------- |
| 1 | 1 | 2022-09-01 | 2022-09-30 |
| 2 | 2 | 2022-09-22 | 2022-09-25 |
| 3 | 3 | 2022-09-19 | 2022-09-25 |
I created SQL
SELECT u.id AS user_id, CONCAT(u.firstName, SPACE(1), u.lastName) AS fullName, IFNULL(SUM(uz.amount), 0) AS suma
FROM users u
LEFT JOIN users_advances uz ON uz.user_id = u.id AND (uz.d_add BETWEEN '2022-09-19' AND '2022-09-25') AND ((uz.status_id = 1) OR (uz.status_id = 2))
LEFT JOIN users_arrivals po ON po.user_id = u.id
WHERE po.start_date <= '2022-09-19' AND po.end_date >= '2022-09-24'
GROUP BY u.id
but it doesnt return me user 2 who had start_date at 2022-09-22.

MySQL select statement missing some fields

I have following statement that is used to select some fields from MySQL DB
select finance_budget_issue.budget_date, SUM(finance_budget_issue.amount) AS amount, finance_vote.office_id as vote_office_id, finance_office.office_head as head,
finance_office.office_name AS office_name,
finance_budget.ref_no, finance_budget_issue.view_status, tbl_signature.office_head as sign_office_head, tbl_signature.name AS name,
tbl_signature.post AS post, tbl_signature.sign_id
from finance_budget_issue
inner join finance_budget on finance_budget.budget_id=finance_budget_issue.budget_id
left join finance_vote on finance_budget_issue.vote_id=finance_vote.vote_id
left join finance_vote_description on finance_vote.description=finance_vote_description.vote_description_id
left join finance_office on finance_budget_issue.office=finance_office.office_id
left join tbl_signature on finance_office.office_id=tbl_signature.office_id
The statement is working fine, but didn't outs the following fields
tbl_signature.office_head as sign_office_head,
tbl_signature.name AS name,
tbl_signature.post AS post
What may be going wrong ? I think that I used incorrect Joins. Can anyone help ?
Tables as follows :
finance_office
+----+-----------+-------------+------+
| id | office_id | office_name | head |
+----+-----------+-------------+------+
| 1 | 48 | A | SS |
| 2 | 69 | B | VV |
+----+-----------+-------------+------+
finance_vote
+---------+-----------+----------------+
| vote_id | office_id | vote |
+---------+-----------+----------------+
| 1 | 48 | 320-1-2-1-1001 |
| 2 | 48 | 320-2-2-2-2002 |
| 3 | 69 | 319-1-2-1-1001 |
| 4 | 69 | 319-1-2-2-1102 |
| 5 | 30 | 318-1-1-2-1101 |
+---------+-----------+----------------+
tbl_signature
+---------+-----------+---------+------------+-------------+
| sign_id | office_id | name | post | office_head |
+---------+-----------+---------+------------+-------------+
| 1 | 48 | Noel | Accountant | Manager |
| 2 | 69 | Jhon | Accountant | Manager |
| 3 | 30 | Micheal | Accountant | Manager |
+---------+-----------+---------+------------+-------------+
finance_budget
+-----------+--------+-------------+
| budget_id | ref_no | budget_date |
+-----------+--------+-------------+
| 1 | Acc/01 | 2020-01-20 |
| 2 | Acc/02 | 2020-01-22 |
+-----------+--------+-------------+
finance_budget_issue
+----+-----------+--------+---------------+-----------------+
| id | budget_id | amount | budget_status | transfer_status |
+----+-----------+--------+---------------+-----------------+
| 1 | 1 | 75000 | issues | Approved |
| 2 | 1 | 22000 | issues | Approved |
| 3 | 2 | 65000 | issues | Approved |
+----+-----------+--------+---------------+-----------------+
Desired Output
+--------+----------------+------+--------+------------------+------+------------+
| amount | vote_office_id | head | ref_no | sign_office_head | name | post |
+--------+----------------+------+--------+------------------+------+------------+
| 75000 | 48 | SS | Acc/01 | Manager | Noel | Accountant |
| 22000 | 48 | SS | Acc/01 | Manager | Noel | Accountant |
| 65000 | 69 | VV | Acc/02 | Manager | Jhon | Accountant |
+--------+----------------+------+--------+------------------+------+------------+
Generated Output (Incorrect)
+--------+----------------+------+--------+------------------+------+------+
| amount | vote_office_id | head | ref_no | sign_office_head | name | post |
+--------+----------------+------+--------+------------------+------+------+
| 75000 | 48 | SS | Acc/01 | | | |
| 22000 | 48 | SS | Acc/01 | | | |
| 65000 | 69 | VV | Acc/02 | | | |
+--------+----------------+------+--------+------------------+------+------+
This is easier to read:
SELECT i.budget_date
, SUM(i.amount) amount
, v.office_id vote_office_id
, o.office_head head
, o.office_name
, b.ref_no
, i.view_status
, s.office_head sign_office_head
, s.name
, s.post
, s.sign_id
FROM finance_budget_issue i
JOIN finance_budget b
ON b.budget_id = i.budget_id
LEFT
JOIN finance_vote v
ON v.vote_id = i.vote_id
LEFT
JOIN finance_vote_description d
ON d.vote_description_id = v.description
LEFT
JOIN finance_office o
ON i.office = o.office_id
LEFT
JOIN tbl_signature s
ON s.office_id = o.office_id
You have an aggregate function (and non-aggregated columns) but no GROUP BY clause; that's not going to work. You have a LEFT JOINed table from which you select no columns; that's pointless.
For further help, see Why should I provide an MCRE for what seems to me to be a very simple SQL query

How do I combine 3 tables in mysql

I need some help here
I have 3 tables which looked like:
user_base_info
+-------+-----------+------------------+------------------+------------------+------------------+
|user_id| real_name | live_province | live_city | live_area_big | live_area_small |
+-------+-----------+------------------+------------------+------------------+------------------+
| 1 | John | 15000000 | 15300000 | 15310000 | 15310003 |
| 2 | Susan | 42000000 | 42140000 | 42140400 | 42140401 |
| 3 | Andy | 12000000 | 58300000 | 58302000 | 58302004 |
| 4 | Knoxvile | 12000000 | 12100000 | 12110000 | 12110002 |
| 5 | Abraham | 13000000 | 50200000 | 50200000 | 11115007 |
| ... | ........ | ... | ... | ... | ... |
|331508 | Donald | 41000000 | 41010000 | 41011200 | 41011202 |
+-------+-----------+------------------+------------------+------------------+------------------+
borrow_progress
+--------+-----------+------------+------------+-------------+
|user_id | borrow_id | state | remark | create_time |
+--------+-----------+------------+------------+-------------+
| 170 | 236 | 10 | waiting | 24/04/17 |
| 170 | 236 | 22 | proceed | 02/02/17 |
| 170 | 236 | 26 | success | 25/04/17 |
| 170 | 236 | 30 | sent | 05/11/17 |
| 172 | 237 | 40 | completed | 03/07/17 |
| ... | ... | ... | ... | ... |
| 353252 | 24112 | 90 | failed | 30/01/17 |
+--------+-----------+------------+------------+-------------+
area
+------------+---------------------+
|code | name |
+------------+---------------------+
| 11000000 | Jawa Tengah |
| 12000000 | Jawa Barat |
| 13000000 | Jawa Timur |
| 14000000 | Sumatera Utara |
| 15000000 | DKI Jakarta |
| ... | ... |
| 41000000 | Di Yogyakarta |
| 42140000 | Kota Singkawang |
| 58300000 | Kota Depok |
| 12100000 | Bandung |
| 50200000 | Kabupaten Sukoharjo |
| 41010000 | Kabupaten Sleman |
| 15310000 | Cilandak |
| 42140400 | Singkawang Barat |
| 41011200 | Mlati |
| 12110000 | Arjasari |
| 15310003 | Gandaria Selatan |
| 41011202 | Sinduadi |
+------------+---------------------+
I want to select the user in table user_base_info which has state = 90 in table borrow_progress and change the live_province, live_city, live_area_big, live_area_small code with name in table area.
I want the result looks like this:
+-------+-----------+------------------+------------------+------------------+------------------+
|user_id| real_name | live_province | live_city | live_area_big | live_area_small |
+-------+-----------+------------------+------------------+------------------+------------------+
|331508 | Donald | Di Yogyakarta | Kabupaten Sleman | Mlati | Sinduadi |
+-------+-----------+------------------+------------------+------------------+------------------+
I have tried
SELECT
*
FROM
borrow_progress a
INNER JOIN
user_base_info b ON a.user_id = b.user_id
INNER JOIN
area c ON c.code = b.live_city
WHERE
state = 90
But this is not what I want.
You must join 4 copies of the table area to the other 2 tables.
Each copy of area will return the name for each of the 4 columns: live_province, live_city, live_area_big and live_area_small:
select u.user_id, u.real_name,
a1.name live_province,
a2.name live_city,
a3.name live_area_big,
a4.name live_area_small
from user_base_info u
inner join borrow_progress b on b.user_id= u.user_id
inner join area a1 on a1.code = u.live_province
inner join area a2 on a2.code = u.live_city
inner join area a3 on a3.code = u.live_area_big
inner join area a4 on a4.code = u.live_area_small
where b.state = 90
If there is a case that the columns live_province, live_city, live_area_big and live_area_small in the table user_base_info to be null then use left joins instead of inner joins.
See the demo.
Results:
| user_id | real_name | live_province | live_city | live_area_big | live_area_small |
| ------- | --------- | ------------- | ---------------- | ------------- | --------------- |
| 331508 | Donald | Di Yogyakarta | Kabupaten Sleman | Mlati | Sinduadi |
Try this:
SELECT
b.user_id
, b.real_name
, (select c1.name from area c1 where code = a.live_province) "live_province"
, live_city
, (select c2.name from area c2 where code = a.live_area_big) "live_area_big"
, (select c3.name from area c3 where code = a.live_area_big) "live_area_small"
FROM borrow_progress a
INNER JOIN user_base_info b ON a.user_id = b.user_id
INNER JOIN area c ON c.code = b.live_city
WHERE state = 90

How to subtract the sum of value using left join?

I have two tables orders and customers:
select * from orders;
+------+---------------------+-------------+--------+
| oid | date | customer_id | amount |
+------+---------------------+-------------+--------+
| 102 | 2009-10-08 00:00:00 | 4 | 300 |
| 100 | 2009-10-08 00:00:00 | 3 | 15000 |
| 101 | 2008-10-08 00:00:00 | 2 | 1300 |
| 105 | 2010-10-08 00:00:00 | 1 | 400 |
| 106 | 2014-12-23 00:00:00 | 3 | 300 |
+------+---------------------+-------------+--------+
select * from customers;
+------+--------+------+-----------+----------+
| id | name | age | address | salary |
+------+--------+------+-----------+----------+
| 1 | ramesh | 32 | Ahmedabad | 2000.00 |
| 2 | khilan | 25 | delhi | 1500.00 |
| 3 | muffy | 22 | bhopal | 8500.00 |
| 4 | suresh | 48 | mumbai | 24000.00 |
| 1 | ramesh | 32 | Ahmedabad | 300.00 |
| 5 | akil | 21 | madurai | 1000.00 |
| 6 | rajesh | 22 | delhi | 5000.00 |
+------+--------+------+-----------+----------+
What I'm trying to do is to do SUM(salary) from customers and subtract it with the SUM(amount) from orders table. I have tried with this query:
SELECT id ,NAME,SUM(salary),SUM(amount),SUM(salary)-SUM(amount)
FROM customers a LEFT JOIN orders b ON a.id=b.customer_id
GROUP BY NAME;
This will return the following result, which some of them return incorrect value:
+------+--------+-------------+-------------+-------------------------+
| id | name | SUM(salary) | SUM(amount) | SUM(salary)-SUM(amount) |
+------+--------+-------------+-------------+-------------------------+
| 5 | akil | 1000.00 | NULL | NULL |
| 2 | khilan | 1500.00 | 1300 | 200.00 |
| 3 | muffy | 17000.00 | 15300 | 1700.00 |
| 6 | rajesh | 5000.00 | NULL | NULL |
| 1 | ramesh | 2300.00 | 800 | 1500.00 |
| 4 | suresh | 24000.00 | 300 | 23700.00 |
+------+--------+-------------+-------------+-------------------------+
My expected output is as following:
+------+--------+-------------+-------------+-------------------------+
| id | name | SUM(salary) | SUM(amount) | SUM(salary)-SUM(amount) |
+------+--------+-------------+-------------+-------------------------+
| 5 | akil | 1000.00 | NULL | 1000 |
| 2 | khilan | 1500.00 | 1300 | 200.00 |
| 3 | muffy | 8500 | 15300 | -6800 |
| 6 | rajesh | 5000.00 | NULL | 5000 |
| 1 | ramesh | 2300.00 | 400 | 1900.00 |
| 4 | suresh | 24000.00 | 300 | 23700.00 |
+------+--------+-------------+-------------+-------------------------+
One way is to make calculation on orders into sub-query.
To cater for NULL value, you can use IFNULL(value,0).
SELECT id,NAME,SUM(salary),amt,SUM(salary)-IFNULL(amt,0)
FROM customers a LEFT JOIN
(SELECT customer_id, SUM(amount) amt FROM orders GROUP BY customer_id) b
ON a.id=b.customer_id
GROUP BY NAME;

MySQL get value using data from three tables

I need to get one value from one table using information from other two.
Here is the structure:
USERS TABLE
+-----------+---------+------------+
| ID | NAME | ZIP |
+-----------+---------+------------+
| 1 | John | 1111-222 |
| 2 | Maria | 2222-555 |
| 3 | José | 3333-505 |
+-----------+---------+------------+
ZIP-MATCH TABLE
+-----------+---------+------------+------------+
| DD | CC | PART1 | PART2 |
+-----------+---------+------------+------------+
| 1 | 1 | 1111 | 101 |
| 1 | 1 | 1111 | 111 |
| 1 | 2 | 1111 | 222 |
| 1 | 3 | 2222 | 333 |
| 2 | 1 | 2222 | 100 |
| 2 | 1 | 2222 | 555 |
| 2 | 2 | 2244 | 222 |
| 2 | 2 | 2244 | 333 |
| 2 | 3 | 2245 | 311 |
| 3 | 1 | 3333 | 111 |
| 3 | 2 | 3333 | 222 |
| 3 | 3 | 3333 | 505 |
+-----------+---------+------------+------------+
AREAS NAME TABLE
+-----------+---------+------------+
| DD | CC | AREA |
+-----------+---------+------------+
| 1 | 1 | Lisboa |
| 1 | 2 | Porto |
| 1 | 3 | Aveiro |
| 2 | 1 | Braga |
| 2 | 2 | Fundão |
| 2 | 3 | Bogas |
| 3 | 1 | Faro |
| 3 | 2 | Leiria |
| 3 | 3 | Covilhã |
+-----------+---------+------------+
What I need to do is a query to get all users from the first table, with all the users data (ID, NAME, ZIP) plus the AREA name.
For this example it would be:
1, John, 1111-222, Porto
2, Maria, 2222-555, Braga
3, José, 3333-505, Covilhã
Thanks in advance,
Miguel.
This is the answer:
SELECT
a.id,
a.name,
a.zip,
c.area
FROM
users a
LEFT JOIN
zip_match b
ON a.zip = concat(b.part1,'-',b.part2)
LEFT JOIN
areas_name c
ON b.dd = c.dd
and b.cc = c.cc;
Assuming your tables were called users, zip_match and areas_name respectively. Not sure of the data types of part1 and part2, they might need to be converted into strings to work in the concat function.
select users.id, users.name, users.zip, areas.area from users u, zipmatch z, areas a
where u.zip = z.part1 + '-' + z.part2
and a.dd = z.dd and a.cc = z.cc
perhaps?