I have a two tables one is products that has productid, productname, customerid1 and quantity
and another customers table that has customerid2,customername and dates
what i want to do is collect all the customerid2 from customers table between two dates.
then match those ids to customerid1 in the products table with a join.
then group all the products by name sum their quantity,
then group all the customers by name for each product and sum their total quantity.
edit: I could use a subquery if necessary or seperate queries entirely. whatever works
**customers**
Column , Column, Column
customerid2:1, name:jon, date:2020
customerid2:2, name:steve, date:2020
customerid2:3, name:ted, date:2020
customerid2:4, name:ned, date:2020
**products**
Column , Column , Column , Column
productid:3 , productname:car, customerid1:1, qty,5
productid:3 , productname:car, customerid1:2, qty,5
productid:1 , productname:boat, customerid1:3, qty,1
productid:1 , productname:boat, customerid1:4, qty,2
productid:3 , productname:car, customerid1:1, qty,5
the final output should be:
car total:15
customer id:1 name:jon qty:10
customer id:2 name:steve qty:5*
boat total:3
customer id:3 name:ted qty:1
customer id:4 name:ned qty:2
my code:
$sql = SELECT customerid2, name, date, productname, SUM(qty)
FROM customers
JOIN ON customerid2 = customerid1
WHERE date BETWEEN '2019' AND '2020'
GROUP BY productid, customerid2
ORDER BY qty
Mysql can't make such an output, but on application level you can use this query, to buld what ever you need
This query:
SELECT
c.customerid2, c.name,p.productname,SUM(qty) total, p1.total_sum
FROM customer c inner JOIN products p ON c.customerid2 = p.customerid1
inner Join (SELECT productid, SUM(qty) total_sum FROM products GROUP BY productid) p1
ON p.productid = p1.productid
WHERE `date` BETWEEN '2019' AND '2020'
GROUP by c.customerid2, c.name,p.productid,p.productname
ORDER by total DESC;
To get a json object as you wanted you need this
SELECT
json_object('product', CONCAT( total_sum,' ',productname), 'customer',json_result) json_result
FROM
(SELECT
productname
,totaL_SUM
,JSON_ARRAYAGG(json_object('customerid', customerid2, 'name', name,'total', total)) json_result
FROM
(SELECT
c.customerid2, c.name,p.productname,SUM(qty) total, p1.total_sum
FROM customer c inner JOIN products p ON c.customerid2 = p.customerid1
inner Join (SELECT productid, SUM(qty) total_sum FROM products GROUP BY productid) p1
ON p.productid = p1.productid
WHERE `date` BETWEEN '2019' AND '2020'
GROUP by c.customerid2, c.name,p.productid,p.productname
ORDER by total DESC) t2
GROUP BY productname,total_sum) t3
CREATE TABLE products (
`productid` INTEGER,
`productname` VARCHAR(4),
`customerid1` INTEGER,
`qty` INTEGER
);
INSERT INTO products
(`productid`, `productname`, `customerid1`, `qty`)
VALUES
('3', 'car', '1', '5'),
('3', 'car', '2', '5'),
('1', 'boat', '3', '1'),
('1', 'boat', '4', '2'),
('3', 'car', '1', '5');
✓
✓
CREATE TABLE customer (
`customerid2` INTEGER,
`name` VARCHAR(5),
`date` INTEGER
);
INSERT INTO customer
(`customerid2`, `name`, `date`)
VALUES
('1', 'jon', '2020'),
('2', 'steve', '2020'),
('3', 'ted', '2020'),
('4', 'ned', '2020');
✓
✓
SELECT
c.customerid2, c.name,p.productname,SUM(qty) total, p1.total_sum
FROM customer c inner JOIN products p ON c.customerid2 = p.customerid1
inner Join (SELECT productid, SUM(qty) total_sum FROM products GROUP BY productid) p1
ON p.productid = p1.productid
WHERE `date` BETWEEN '2019' AND '2020'
GROUP by c.customerid2, c.name,p.productid,p.productname
ORDER by total DESC;
customerid2 | name | productname | total | total_sum
----------: | :---- | :---------- | ----: | --------:
1 | jon | car | 10 | 15
2 | steve | car | 5 | 15
4 | ned | boat | 2 | 3
3 | ted | boat | 1 | 3
SELECT json_object('product', CONCAT( total_sum,' ',productname), 'customer',
json_object('customerid', customerid2, 'name', name,'total', total)) json_result
FROM
(SELECT
c.customerid2, c.name,p.productname,SUM(qty) total, p1.total_sum
FROM customer c inner JOIN products p ON c.customerid2 = p.customerid1
inner Join (SELECT productid, SUM(qty) total_sum FROM products GROUP BY productid) p1
ON p.productid = p1.productid
WHERE `date` BETWEEN '2019' AND '2020'
GROUP by c.customerid2, c.name,p.productid,p.productname
ORDER by total DESC) t2
| json_result |
| :-------------------------------------------------------------------------------- |
| {"product": "15 car", "customer": {"name": "jon", "total": 10, "customerid": 1}} |
| {"product": "15 car", "customer": {"name": "steve", "total": 5, "customerid": 2}} |
| {"product": "3 boat", "customer": {"name": "ned", "total": 2, "customerid": 4}} |
| {"product": "3 boat", "customer": {"name": "ted", "total": 1, "customerid": 3}} |
SELECT
json_object('product', CONCAT( total_sum,' ',productname), 'customer',json_result) json_result
FROM
(SELECT
productname
,totaL_SUM
,JSON_ARRAYAGG(json_object('customerid', customerid2, 'name', name,'total', total)) json_result
FROM
(SELECT
c.customerid2, c.name,p.productname,SUM(qty) total, p1.total_sum
FROM customer c inner JOIN products p ON c.customerid2 = p.customerid1
inner Join (SELECT productid, SUM(qty) total_sum FROM products GROUP BY productid) p1
ON p.productid = p1.productid
WHERE `date` BETWEEN '2019' AND '2020'
GROUP by c.customerid2, c.name,p.productid,p.productname
ORDER by total DESC) t2
GROUP BY productname,total_sum) t3
| json_result |
| :--------------------------------------------------------------------------------------------------------------------------------- |
| {"product": "3 boat", "customer": [{"name": "ned", "total": 2, "customerid": 4}, {"name": "ted", "total": 1, "customerid": 3}]} |
| {"product": "15 car", "customer": [{"name": "jon", "total": 10, "customerid": 1}, {"name": "steve", "total": 5, "customerid": 2}]} |
db<>fiddle here
Related
I Have this query
SELECT DATE_FORMAT(bookings.start_at, '%m/%d/%Y') as "Date",
CASE WHEN payment.type = "CASH" THEN sum(payment.amount) end as "Cash" ,
CASE WHEN payment.type = "Credit" THEN sum(payment.amount) end as "Credit"
from orders
inner join bookings on bookings.id = orders.booking_id
inner join payment on payment.order_id = orders.id
where (bookings.start_at BETWEEN '2022-03-09' AND '2022-03-09 23:59:00')
group by payment.type;
And it returning like this
Date | Cash | Credit
2022/03/09 | NULL | NULL
2022/03/09 | 2000 | NULL
2022/03/09 | NULL | 5000
What i want to achieve is like this
Date | Cash | Credit
2022/03/09 | 2000 | 5000
i already tried GROUP BY for start_at but it return a different kind of time but same date
SELECT DATE_FORMAT(bookings.start_at, '%m/%d/%Y') as `Date`,
SUM(CASE WHEN payment.type = "CASH"
THEN payment.amount
ELSE 0
END) as `Cash`,
SUM(CASE WHEN payment.type = "Credit"
THEN payment.amount
ELSE 0
END) as `Credit`
from orders
inner join bookings on bookings.id = orders.booking_id
inner join payment on payment.order_id = orders.id
where bookings.start_at BETWEEN '2022-03-09' AND '2022-03-09 23:59:00'
group by 1;
I have two tables in MySQL:
Table 1 - WORKORDERS
ID
QUANTITY
1
2
2
1
Table 2 - ITEMSINWORKORDERS
ID
WORKORDER
1
1
2
1
3
2
I have a query:
SELECT WORKORDERS.ID
, WORKORDERS.QUANTITY AS NOMINAL_QTY
, COUNT(ITEMSINWORKORDERS.WORKORDER) AS ENTERED_QTY
FROM WORKORDERS JOIN ITEMSINWORKORDERS ON
ITEMSINWORKORDERS.WORKORDER = WORKORDERS.ID
WHERE WORKORDERS.QUANTITY >
( SELECT COUNT(ITEMSINWORKORDERS.WORKORDER )
FROM WORKORDERS INNER JOIN ITEMSINWORKORDERS ON
ITEMSINWORKORDERS.WORKORDER = WORKORDERS.ID
)
Originally, I had a left outer join in my statement, so I switched it to inner in hopes of getting an empty set. How can I make it return an empty set whenever there aren't any work orders with missing entries?
Which is intended to find all work orders where not all items have been entered, and the nominal quantity, entered in the WORKORDERS table is greater than the number of records in ITEMSINWORKORDERS corresponding to that work order. I expected to return an empty set. Instead, I get
ID
NOMINAL_QTY
ENTERED_QTY
NULL
NULL
0
Originally, I had a left outer join in my statement, so I switched it to inner in hopes of getting an empty set.
Addendum:
I tried solving this myself using NULLIF thus:
SELECT WORKORDERS.ID
, WORKORDERS.QUANTITY AS NOMINAL_QTY
, NULLIF(COUNT(ITEMSINWORKORDERS.WORKORDER), 0) AS ENTERED_QTY
FROM WORKORDERS JOIN ITEMSINWORKORDERS ON
ITEMSINWORKORDERS.WORKORDER = WORKORDERS.ID
WHERE WORKORDERS.QUANTITY >
( SELECT COUNT( ITEMSINWORKORDERS.WORKORDER )
FROM WORKORDERS INNER JOIN ITEMSINWORKORDERS ON
ITEMSINWORKORDERS.WORKORDER = WORKORDERS.ID
)
What I got was frustrating:
ID
NOMINAL_QTY
ENTERED_QTY
NULL
NULL
NULL
I don't know what you expoect as your qiery delivers no rows.
But for count to work you need a GROUP BY
CREATE TABLE WORKORDERS (
`ID` INTEGER,
`QUANTITY` INTEGER
);
INSERT INTO WORKORDERS
(`ID`, `QUANTITY`)
VALUES
('1', '2'),
('2', '1');
CREATE TABLE ITEMSINWORKORDERS (
`ID` INTEGER,
`WORKORDER` INTEGER
);
INSERT INTO ITEMSINWORKORDERS
(`ID`, `WORKORDER`)
VALUES
('1', '1'),
('2', '1'),
('3', '2');
SELECT WORKORDERS.ID
, WORKORDERS.QUANTITY AS NOMINAL_QTY
, COUNT(ITEMSINWORKORDERS.WORKORDER) AS ENTERED_QTY
FROM WORKORDERS JOIN ITEMSINWORKORDERS ON
ITEMSINWORKORDERS.WORKORDER = WORKORDERS.ID
WHERE WORKORDERS.QUANTITY >
( SELECT COUNT(ITEMSINWORKORDERS.WORKORDER )
FROM WORKORDERS INNER JOIN ITEMSINWORKORDERS ON
ITEMSINWORKORDERS.WORKORDER = WORKORDERS.ID
)
GROUP BY WORKORDERS.ID
, WORKORDERS.QUANTITY
ID | NOMINAL_QTY | ENTERED_QTY
-: | ----------: | ----------:
SELECT COUNT(ITEMSINWORKORDERS.WORKORDER )
FROM WORKORDERS INNER JOIN ITEMSINWORKORDERS ON
ITEMSINWORKORDERS.WORKORDER = WORKORDERS.ID
| COUNT(ITEMSINWORKORDERS.WORKORDER ) |
| ----------------------------------: |
| 3 |
db<>fiddle here
My query is
SELECT (
SELECT invoice_custom_fieldvalue FROM ip_invoice_custom WHERE invoice_id ='2474' AND invoice_custom_fieldid = '9'
) AS 'Claim Number',
(
SELECT invoice_custom_fieldvalue FROM ip_invoice_custom WHERE invoice_id ='2474' AND invoice_custom_fieldid = '7'
) AS 'Client Name',
(
SELECT invoice_custom_fieldvalue FROM ip_invoice_custom WHERE invoice_id ='2474' AND invoice_custom_fieldid = '8'
) AS 'Employer',
(
SELECT invoice_item_subtotal FROM ip_invoice_amounts WHERE invoice_amount_id ='2474'
) AS 'Invoice Amount',
(
SELECT invoice_item_tax_total FROM ip_invoice_amounts WHERE invoice_amount_id ='2474'
) AS 'Tax',
(
SELECT invoice_item_subtotal FROM ip_invoice_amounts WHERE invoice_amount_id ='2474'
) AS 'Tax1',
(
SELECT CONCAT('CAD') FROM ip_invoice_amounts WHERE invoice_amount_id ='2474'
) AS 'Currency',
(
SELECT invoice_date_created FROM ip_invoices WHERE invoice_id ='2474'
) AS 'Date',
(
SELECT client_name FROM ip_clients c INNER JOIN ip_invoices i ON c.client_id = i.client_id WHERE i.invoice_id ='2474'
) AS 'Requested by',
(
SELECT item_description FROM ip_invoice_items p WHERE p.invoice_id
) AS 'Transaction Subtype';
This is the result without the last select:
Claim Number Client Name Employer Invoice Amount Tax Tax1 Currency Date Requested by
12345 John Smith NULL 3326.99 0.00 0.00 CAD 2019-12-04 ATTN: Joe Smith
ip_invoice_items table looks like:
item_id invoice_id item_description
1 2474 Some product
2 2474 Some other product
3 2474 Some other other product
Desired output:
Claim Number Client Name Employer Invoice Amount Tax Tax1 Currency Date Requested by Item Description
12345 John Smith NULL 3326.99 0.00 0.00 CAD 2019-12-04 ATTN: Joe Smith Some product
12345 John Smith NULL 3326.99 0.00 0.00 CAD 2019-12-04 ATTN: Joe Smith Some other product
12345 John Smith NULL 3326.99 0.00 0.00 CAD 2019-12-04 ATTN: Joe Smith Some other other product
There are multiple item descriptions for each invoice_id (Last select statement). How can I rewrite this so I am getting a result that will add rows for each item description?
There are 5 tables involved and you can start with ip_invoice_custom and LEFT join the other 4:
SELECT ic.`Claim Number`, ic.`Client Name`, ic.`Employer`,
ia.invoice_item_subtotal `Invoice Amount`,
ia.invoice_item_tax_total `Tax`,
ia.invoice_item_subtotal `Tax1`,
'CAD' `Currency`,
i.invoice_date_created `Date`,
c.client_name `Requested by`,
ii.item_description `Transaction Subtype`
FROM (
SELECT invoice_id,
MAX(CASE WHEN invoice_custom_fieldid = '9' THEN invoice_custom_fieldvalue END) `Claim Number`,
MAX(CASE WHEN invoice_custom_fieldid = '7' THEN invoice_custom_fieldvalue END) `Client Name`,
MAX(CASE WHEN invoice_custom_fieldid = '8' THEN invoice_custom_fieldvalue END) `Employer`
FROM ip_invoice_custom
WHERE invoice_id ='2474' AND invoice_custom_fieldid IN ('7', '8', '9')
GROUP BY invoice_id
) ic
LEFT JOIN ip_invoice_amounts ia ON ia.invoice_amount_id = ic.invoice_id
LEFT JOIN ip_invoices i ON i.invoice_id = ic.invoice_id
LEFT JOIN ip_clients c ON c.client_id = i.client_id
LEFT JOIN ip_invoice_items ii ON ii.invoice_id = ic.invoice_id
You could do this all with one select statement by joining the tables on the invoice id. For the custom table, you can join that table 3 times to get the value for each custom value.
Here is a rough sketch of what that would look like:
SELECT cn1.invoice_custom_fieldvalue as 'Claim Number',
cn2.invoice_custom_fieldvalue as 'Client Name',
em.invoice_custom_fieldvalue as 'Employer',
ip_invoice_amounts.invoice_item_subtotal as 'Invoice Amount',
ip_invoice_amounts.invoice_item_tax_total as 'Tax',
CONCAT('CAD') as 'Currency',
ip_clients.client_name as 'Requested by',
ip_invoice_items.item_description as 'Transaction Subtype'
FROM ip_invoice_custom cn1
JOIN ip_invoice_custom cn2
ON cn1.invoice_id=cn2.invoice_id
JOIN ip_voice_custom em
ON cn1.invoice_id=em.invoice_id
JOIN ip_invoice_amounts
ON cn1.invoice_id=invoice_amounts.invoice_amount_id
JOIN ip_invoices
ON cn1.invoice_id=ip_invoices.invoice_id
JOIN ip_clients
ON ip_invoices.client_id=ip_clients.client_id
JOIN ip_invoice_items
ON cn1.invoice_id=ip_invoice_items.invoice_id
WHERE cn1.invoice_custom_fieldid = '9'
AND cn2.invoice_custom_fieldid = '7'
AND em.invoice_custom_fieldid = '8'
AND cn1.invoice_id = '2474';
I am not sure what you are doing for the currency line so that might need to be edited but this does the entire search in one select statement.
Working with your original code you could also join your select statement with the ip_invoice_items table. You could join the larger select statement, not including the last sub select, with the ip_invoice_table where the ip_invoice_id equals the value you are looking for. Here is a rough sketch of what you could do:
SELECT Claim_Number, Client_Name_Employer, Invoice_Amount, Tax,
Tax1_Currency, Date, item_description
FROM ip_invoice_items JOIN
( ... ) as ip_info
WHERE ip_invoice_items.item_id = '2474';
In the parenthesis you can include the larger select statement. I also recommend giving the sub_select statements non-string names and beautifying the output in the outer select statement.
I have two tables as given below...
INSERT INTO `tbl_project_skills` (`id`, `projectId`, `skillId`) VALUES
(17, 2, 44),
(27, 2, 43),
(31, 2, 78),
(33, 142, 79),
(35, 123, 88);
INSERT INTO `tbl_user_skills` (`id`, `userId`, `skillId`) VALUES
(2, 1, 44),
(3, 1, 78),
(5, 23, 45),
(6, 1, 36),
(7, 23, 88);
I want to find that how many skills are matched of user with each project like below
-----------------------------------------------------
userId | projectId | number_of_matched_skills
-----------------------------------------------------
1 | 2 | 2
1 | 142 | 0
1 | 123 | 0
23 | 2 | 0
23 | 142 | 0
23 | 123 | 1
------------------------------------------------------
I've tried below solution for the same...
SELECT ps.projectId, us.userId, ps.skillId AS pskillid, us.skillId AS uskillid, #points_veri:= (CASE WHEN '44' IN(ps.skillId) THEN 1 ELSE 0 END) + (CASE WHEN '43' IN(ps.skillId) THEN 1 ELSE 0 END) + (CASE WHEN '78' IN(ps.skillId) THEN 1 ELSE 0 END) AS number_of_matched_skills FROM tbl_user_skills AS us, tbl_project_skills AS ps
But I can't get it right. Hope you guys can give a hint.
I think you may have another table for store user and project, or this query will need get userId from tbl_user_skills and projectId from tbl_project_skills first, then do cross join, then join tbl_user_skills and tbl_project_skills to do aggregation:
select
main.userId,
main.projectId,
count(ps.projectId) as number_of_matched_skills
from (
select u.userId, p.projectId
from (
select distinct projectId from tbl_project_skills
) p
cross join (
select distinct userId from tbl_user_skills
) u
) main
left join tbl_user_skills us on us.userId = main.userId
left join tbl_project_skills ps on ps.skillId = us.skillId and main.projectId = ps.projectId
group by main.userId, main.projectId
Here is a demo in rextester.com.
Another option without having another table. Make an OUTER JOIN and then a GROUP BY on skillId.
SELECT userid,
projectid,
SUM(CASE WHEN p.skillId>1 AND u.skillId>1 THEN 1 ELSE 0 END) AS skills
FROM tbl_user_skills u
FULL OUTER JOIN tbl_project_skills p
ON u.skillId = p.skillId
GROUP BY userid, projectid
ORDER BY skills DESC
I'm trying to do the sum when:
date_ini >= initial_date AND final_date <= date_expired
And if it is not in the range will show the last net_insurance from insurances
show last_insurance when is not in range
Here my tables:
POLICIES
ID POLICY_NUM DATE_INI DATE_EXPIRED TYPE_MONEY
1, 1234, "2013-01-01", "2014-01-01" , 1
2, 5678, "2013-02-01", "2014-02-01" , 1
3, 9123, "2013-03-01", "2014-03-01" , 1
4, 4567, "2013-04-01", "2014-04-01" , 1
5, 8912, "2013-05-01", "2014-05-01" , 2
6, 3456, "2013-06-01", "2014-06-01" , 2
7, 7891, "2013-07-01", "2014-07-01" , 2
8, 2345, "2013-08-01", "2014-08-01" , 2
INSURANCES
ID POLICY_ID INITIAL_DATE FINAL_DATE NET_INSURANCE
1, 1, "2013-01-01", "2014-01-01", 100
2, 1, "2013-01-01", "2014-01-01", 200
3, 1, "2013-01-01", "2014-01-01", 400
4, 2, "2011-01-01", "2012-01-01", 500
5, 2, "2013-01-01", "2014-01-01", 600
6, 3, "2013-01-01", "2014-01-01", 100
7, 4, "2013-01-01", "2014-01-01", 200
I should have
POLICY_NUM NET
1234 700
5678 600
9123 100
4567 200
Here is what i tried
SELECT p.policy_num AS policy_num,
CASE WHEN p.date_ini >= i.initial_date
THEN SUM(i.net_insurance)
ELSE (SELECT max(id) FROM insurances GROUP BY policy_id) END as net
FROM policies p
INNER JOIN insurances i ON p.id = i.policy_id AND p.date_ini >= i.initial_date
GROUP BY p.id
Here is my query http://sqlfiddle.com/#!2/f6077b/16
Somebody can help me with this please?
Is not working when is not in the range it would show my last_insurance instead of sum
Try it this way
SELECT p.policy_num, SUM(i.net_insurance) net_insurance
FROM policies p JOIN insurances i
ON p.id = i.policy_id
AND p.date_ini >= i.initial_date
AND p.date_expired <= i.final_date
GROUP BY i.policy_id, p.policy_num
UNION ALL
SELECT p.policy_num, i.net_insurance
FROM
(
SELECT MAX(i.id) id
FROM policies p JOIN insurances i
ON p.id = i.policy_id
AND (p.date_ini < i.initial_date
OR p.date_expired > i.final_date)
GROUP BY i.policy_id
) q JOIN insurances i
ON q.id = i.id JOIN policies p
ON i.policy_id = p.id
Output:
| POLICY_NUM | NET_INSURANCE |
|------------|---------------|
| 1234 | 700 |
| 5678 | 600 |
| 9123 | 100 |
| 4567 | 200 |
Here is SQLFiddle demo
This will ensure that you only get the last insurance if the policy has no insurances within the policy period.
SELECT policy_num, SUM(IF(p.cnt > 0, p.net_insurance, i.net_insurance)) AS net_insurance
FROM
(
SELECT
p.id,
p.policy_num,
SUM(IF(p.date_ini >= i.initial_date AND p.date_expired <= i.final_date,
i.net_insurance, 0)) AS net_insurance,
SUM(IF(p.date_ini >= i.initial_date AND p.date_expired <= i.final_date,
1, 0)) AS cnt,
MAX(IF(p.date_ini >= i.initial_date AND p.date_expired <= i.final_date,
0, i.id)) AS max_i_id
FROM policies p
INNER JOIN insurances i ON p.id = i.policy_id
GROUP BY p.id
) as p
LEFT JOIN insurances i ON i.id = p.max_i_id
GROUP BY p.id
Here is my SQLFiddle
Try splitting grouping from conditioning :)
SELECT
policy_num
, CASE
WHEN TRUE
AND p.date_ini <= src.initial_date
AND p.date_expired >= src.final_date
THEN src.sum_insurances
ELSE i.net_insurance
END AS something
FROM (
SELECT
max(id) AS latest_id
, sum(net_insurance) AS sum_insurances
, initial_date
, final_date
, policy_id
FROM insurances
GROUP BY policy_id
) src
JOIN policies p ON p.id = src.policy_id
JOIN insurances i ON i.id = src.latest_id
ORDER BY p.id