Get query result of multiple row in single row? - mysql

I have one table with product details in each row where each item is unique.Second table is tax basis which have multiple tax for any single item. I want result which should have single row for each item and all tax related to that item should be in that row with other details
item
item_id name type
1. bike vehicle
tax
id tax_name tax_rate item_id
1. tax1 12 1
2. tax2 13 1
3. tax3 14 1
Result should be:
id name type tax_name_1 tax_rate_1 tax_name_2 tax_rate_2 tax_name_3 tax_rate_3
1 bike vehicle tax1 12 tax2 13 tax3 14

This is a typical table pivot issue, try this:
select
item.*,
max(case when tax.id = 1 then tax_name end) as tax_name_1,
max(case when tax.id = 1 then tax_rate end) as tax_rate_1,
max(case when tax.id = 2 then tax_name end) as tax_name_2,
max(case when tax.id = 2 then tax_rate end) as tax_rate_2,
max(case when tax.id = 3 then tax_name end) as tax_name_3,
max(case when tax.id = 3 then tax_rate end) as tax_rate_3
from item
join tax
group by item.id

I think simple inner join will do this task for you
SELECT item.*, tax.taxname,tax.taxrate
FROM table1
INNER JOIN tax
ON item.id=tax.id;

Related

Sum delivered values and subtract it from the received values with the same name mysql

I have this table
table name: com_inv
item_name amount date_added
item 1 1 06/06/2015
item 2 2 07/06/2015
item 3 3 08/06/2015
item 1 10 09/06/2015
item 2 20 10/06/2015
item 3 30 11/06/2015
table name: sls_ordrs
item_name amount order_status date_received
item 1 1 received 06/06/2015
item 2 1 delivered
item 3 2 received 08/06/2015
item 1 5 received 09/06/2015
item 2 5 delivered
item 3 2 received 11/06/2015
What I want to achieve is, per item, subtract the sum of the amount in sls_ordrs that have been "received" from the sum of the amount in com_inv. The resulting table should be like this:
Item Name Stocked Dispensed Remaining
item 1 11 6 5
item 2 22 0 22
item 3 33 4 29
If I use SQL Server, I would just use the CTE but with MySql I need your help. This is the code I came up so far...
SELECT
a.item_name,
b.stocked AS 'Stocked',
sum(a.amount) AS 'Dispensed',
IFNULL(b.stocked, 0) - IFNULL(a.amount, 0) AS 'Remaining'
FROM
sls_ordrs a
LEFT JOIN (
SELECT
item_name AS 'item_name',
SUM(amount) AS 'stocked'
FROM
com_inv
GROUP BY
item_name
) b ON a.item_name = b.item_name
WHERE
a.order_status = 'received'
GROUP BY
item_name
The stocked column here gives me a null value.
Use this Query. Hope it should be working fine.
SQL FIDDLE DEMO
SELECT
I.item_name,
I.Stocked,
S.Dispensed,
COALESCE (I.Stocked, 0) - COALESCE (S.Dispensed, 0) AS Remaining
FROM
(
SELECT
item_name AS 'item_name',
SUM(amount) AS 'Stocked'
FROM
com_inv
GROUP BY
item_name
) I
LEFT JOIN (
SELECT
item_name,
order_status,
SUM(amount) AS Dispensed
FROM
sls_ordrs
WHERE
order_status = 'received'
GROUP BY
item_name
) S ON I.item_name = S.item_name;

ORDER BY WITH ROLL UP

SELECT a.invoice_id,
invoice_no,
a.cs_no,
identity,
name,
model,
body_color,
lot_no,
key_no,
serial_no,
location,
buyoff_date,
received_date,
tagged_date,
invoice_date,
a.pullout_date,
vin_no,
engine_no,
order_no,
b.approve,
COUNT(a.cs_no) AS buyoff_count,
SUM(CASE WHEN received_date IS NULL THEN 0 ELSE 1 END) AS received_count,
SUM(CASE WHEN tagged_date IS NULL THEN 0 ELSE 1 END) AS tagged_count,
SUM(CASE WHEN invoice_date IS NULL THEN 0 ELSE 1 END) AS invoice_count,
SUM(CASE WHEN a.pullout_date IS NULL THEN 0 ELSE 1 END) AS pullout_count
FROM buy_off a
LEFT JOIN pull_out b
ON a.invoice_id = b.invoice_id
AND a.cs_no = b.cs_no
WHERE tagged_date IS NOT NULL
AND invoice_date IS NULL
GROUP BY identity, tagged_date, invoice_id WITH ROLLUP
My above code have output like this:
invoice_id identity tagged_date
1 a 2/5/2015
total = 1
2 a 2/6/2015
3 a 2/6/2015
total = 2
4 b 2/5/2015
total = 1
5 b 2/6/2015
total = 1
grand total = 5
But this is what i want:
invoice_id identity tagged_date
1 a 2/5/2015
2 a 2/6/2015
3 a 2/6/2015
total = 3
4 b 2/5/2015
5 b 2/6/2015
total = 2
grand total = 5
Can you guys please help to achieve the above output.....Thanks in advance. :D

MySQL select using row counts and grouping

I have 2 tables, orders and order_lineitems.
orders contains the order status info (sold date, invoice no, type of sale, etc)
order_lineitems contains the item(s) for each order in a one to many relationship.
Since we provide shipping info by line item, ship_date is in the order_lineitems table, null if not shipped, a date if it is shipped.
I am trying to pull the orders where all items have shipped by comparing the number of line item rows against the line item rows that have a ship date. While I have successfully pulled all that info, I am unable to make the last step, limiting the result set to include only the completely shipped orders (number of rows = number of rows where ship_date is not null).
I know I am missing something simple, but just don't see it..
select sum(custom.lineitems) as totalitems, sum(custom.shipped) as totalshipped,
custom.invoice, z.shipregion
from (
select a.invoice, count(a.invoice) as lineitems, 0 as shipped
from order_lineitem a
group by a.invoice
UNION ALL
select b.invoice, 0 as notshipped, count(b.ship_date) as shipped
from order_lineitem b
where b.ship_date is not null
group by b.invoice
) as custom
left join orders z on custom.invoice = z.invoice
where z.result = 0
and z.respmsg like 'Approved%'
and z.shipregion <> 'PENDING'
and z.cancelorder = 0
group by custom.invoice;
This returns a result set like so (one row for each invoice in the DB)
totalitems totalshipped invoice shipregion
4 2 1000 REGION08
1 1 10001 REGION07
1 1 10004 REGION05
3 1 10006 REGION05
2 2 10007 REGION04
1 1 10008 REGION08
7 7 10009 REGION01
1 1 1001 REGION08
What I am looking for is a result set like this - only where totalitems = totalshipped
totalitems totalshipped invoice shipregion
1 1 10001 REGION07
1 1 10004 REGION05
2 2 10007 REGION04
1 1 10008 REGION08
7 7 10009 REGION01
1 1 1001 REGION08
Use HAVING clause
SELECT a.invoice, z.shipregion, COUNT(a.invoice) AS lineitems,
SUM(CASE WHEN a.ship_date IS NOT NULL THEN 1 ELSE 0 END) AS shipped
FROM order_lineitem a
LEFT JOIN orders z ON a.invoice = z.invoice AND z.result = 0 AND z.cancelorder = 0 AND
z.respmsg LIKE 'Approved%' AND z.shipregion <> 'PENDING'
GROUP BY a.invoice HAVING lineitems = shipped
OR
SELECT a.invoice, a.shipregion, a.lineitems, a.shipped
FROM (SELECT a.invoice, z.shipregion, COUNT(a.invoice) AS lineitems,
SUM(CASE WHEN a.ship_date IS NOT NULL THEN 1 ELSE 0 END) AS shipped
FROM order_lineitem a
LEFT JOIN orders z ON a.invoice = z.invoice AND z.result = 0 AND z.cancelorder = 0 AND
z.respmsg LIKE 'Approved%' AND z.shipregion <> 'PENDING'
GROUP BY a.invoice
) AS a WHERE a.lineitems = a.shipped
One more outer query needed.
select * from
(
\\Your whole query here
) as Result
where Result.totalitems = Result.totalshipped

SQL select ordered product quantities based on delivery date sorted by week

I am not sure if my question is clear but what I need is quite complex query. I am unable to put it together myself.
We have tables orders, order_items, products, deliveries and delivery_items. Orders is the main order table. Order_items table holds the list of ordered products in certain order. Products is the main products table and deliveries/delivery_items tables hold the list of delivered order_items (we can deliver entire order or only partially).
This is the 'stripped down' table structure:
ORDERS:
ID ORDER_NUMBER DELIVERY_DATE STATUS
-------------------------------------------------
1 2013-00001 Unixtimestamp Closed
2 2013-00002 Unixtimestamp Open
...
PRODUCTS:
ID CODE
-----------------------
1 Product 1
2 Product 2
3 Product 3
...
ORDER ITEMS:
ID ORDER_ID PRODUCT_ID QTY
-----------------------------------------
1 1 1 2
2 1 2 5
3 1 3 1
4 2 3 10
DELIVERIES:
ID ORDER_ID DELIVERY_NUMBER TYPE
---------------------------------------------
1 1 2013-00001 Full
2 2 2013-00002 Partial
...
DELIVERY_ITEMS:
ID DELIVERY_ID ORDER_ITEM_ID QTY
------------------------------------------
1 1 1 2
2 1 2 5
3 1 3 1
4 2 4 5
...
Our production demands view where all non-delivered order_items(products) are listed by quantities in the upcoming week schedule. What I need is something like this (quantities here are random):
Product Overdue W0 W1 W2 W3 W4 W5 Later Total
-------------------------------------------------------------------------
Product 1 1 2 0 0 0 0 0 0 3
Product 2 0 3 5 1 0 0 0 4 13
Product 3 2 4 0 7 5 0 0 0 18
...
The entire view is based on current time and order's delivery_date field. The query would need to get ordered product quantities from all open orders, check if some of there products were maybe already delivered and subtract delivered quantities, and on the end sort the result quantities as shown above.
UPDATE: here is SQL Fiddle with above structure with some data http://sqlfiddle.com/#!2/88891/4
---Using Fiddle provided (http://sqlfiddle.com/#!2/88891/34/0)
SELECT P.Name,
sum(case when DATEDIFF(FROM_UNIXTIME(Delivery_date),curDate())<=0 then coalesce(OI.Quantity,0)-coalesce(DI.Quantity,0) else 0 END) AS Overdue,
sum(case when DATEDIFF(FROM_UNIXTIME(Delivery_date),curDate())<=7 and DATEDIFF(FROM_UNIXTIME(Delivery_date),curDate())>0 then coalesce(OI.Quantity,0)-coalesce(DI.Quantity,0) else 0 END) as W0,
sum(case when DATEDIFF(FROM_UNIXTIME(Delivery_date),curDate())<=14 and DATEDIFF(FROM_UNIXTIME(Delivery_date),curDate())>7 then coalesce(OI.Quantity,0)-coalesce(DI.Quantity,0) else 0 END) as W1,
sum(case when DATEDIFF(FROM_UNIXTIME(Delivery_date),curDate())<=21 and DATEDIFF(FROM_UNIXTIME(Delivery_date),curDate())>14 then coalesce(OI.Quantity,0)-coalesce(DI.Quantity,0) else 0 END) as W2,
sum(case when DATEDIFF(FROM_UNIXTIME(Delivery_date),curDate())<=28 and DATEDIFF(FROM_UNIXTIME(Delivery_date),curDate())>21 then coalesce(OI.Quantity,0)-coalesce(DI.Quantity,0) else 0 END) as W3,
sum(case when DATEDIFF(FROM_UNIXTIME(Delivery_date),curDate())<=35 and DATEDIFF(FROM_UNIXTIME(Delivery_date),curDate())>28 then coalesce(OI.Quantity,0)-coalesce(DI.Quantity,0) else 0 END) as W4,
sum(case when DATEDIFF(FROM_UNIXTIME(Delivery_date),curDate())<=42 and DATEDIFF(FROM_UNIXTIME(Delivery_date),curDate())>35 then coalesce(OI.Quantity,0)-coalesce(DI.Quantity,0) else 0 END) as W5,
sum(case when DATEDIFF(FROM_UNIXTIME(Delivery_date),curDate())>42 then coalesce(OI.Quantity,0)-coalesce(DI.Quantity,0) else 0 END) as Later,
sum(coalesce(OI.Quantity,0)-coalesce(DI.Quantity,0)) as Total
FROM ORDERS O
INNER JOIN ORDER_ITEMS OI
ON OI.Order_ID = O.ID
INNER JOIN PRODUCTS P on
P.ID = OI.Product_ID
LEFT JOIN DELIVERIES D
ON D.Order_ID = O.ID
LEFT JOIN DELIVERY_ITEMS DI
ON DI.Delivery_ID = D.ID
AND OI.ID = DI.Order_Item_ID
WHERE coalesce(DI.Quantity,0) < OI.Quantity
GROUP BY P.Name
Thanks for the fiddle. This takes care of all the remaining syntax errors. and formats to include 0 in the results.
Coalesce, takes first non-null value in an unlimited series.
FROM_UNIXTIME converts into to valid date time for comparison using datediff.
else statments handle situations when no data matches critiera thus 0 is
evaluated.
where clause eliminates orders with all items delivered or more than all items ordered delivered. (Thus items closed will still be included since they are not fully shipped!)
To get you started, here are a couple of joins:
SELECT o.ORDER_NUMBER, p.CODE, oi.QTY
FROM orders o
JOIN order_items oi ON oi.ORDER_ID = o.ID
JOIN products p ON p.ID = oi.PRODUCT_ID
And:
SELECT d.DELIVERY_NUMBER, d.ORDER_ID, di.ORDER_ITEM_ID, di.QTY
FROM deliveries d
JOIN delivery_items di ON di.DELIVERY_ID = d.ID
What would you have to do to tie those together?

MySQL GROUP BY and JOIN

Guys what's wrong with this SQL query:
$sql = "SELECT
res.Age,
res.Gender,
answer.*,
$get_sum,
SUM(CASE WHEN res.Gender='Male' THEN 1 else 0 END) AS males,
SUM(CASE WHEN res.Gender='Female' THEN 1 else 0 END) AS females
FROM Respondents AS res
INNER JOIN Answers as answer
ON answer.RespondentID=res.RespondentID
INNER JOIN Questions as question
ON answer.Answer=question.id
WHERE answer.Question='Q1'
GROUP BY res.Age
ORDER BY res.Age ASC";
the $get_sum is an array of sql statement derived from another table:
$sum[]= "SUM(CASE WHEN answer.Answer=".$db->f("id")." THEN 1 else 0 END) AS item".$db->f("id");
$get_sum = implode(', ', $sum);
the query above return these values:
Age: 20
item1 0
item2 1
item3 1
item4 1
item5 0
item6 0
Subtotal for Age 20 3
Age: 24
item1 2
item2 2
item3 2
item4 2
item5 1
item6 0
Subtotal for Age 24 9
It should return:
Subtotal for Age 20 1
Subtotal for Age 24 2
In my sample data there are 3 respondents 2 are 24 yrs of age and the other one is 20 years old.
I want to total the number of respondents per age.
$sql = "SELECT
res.Age,
COUNT(1) AS SubTotalRespondentsByAge
$get_sum,
SUM(CASE WHEN res.Gender='Male' THEN 1 else 0 END) AS males,
SUM(CASE WHEN res.Gender='Female' THEN 1 else 0 END) AS females
FROM Respondents AS res
INNER JOIN Answers as answer
ON answer.RespondentID=res.RespondentID
INNER JOIN Questions as question
ON answer.Answer=question.id
WHERE answer.Question='Q1'
GROUP BY res.Age
ORDER BY res.Age ASC"
You cannot include any columns in the select clause that have a many-to-one relationship with age. I've thus removed the res.gender and answers.* columns. What you want is count(1) of the groups (since you group by res.Age).