Combine multiple select statement in one result table - mysql

I have two tables, one for sales and another for stock.
I want to select location id, item id, size id and sales qty from sales table, while I want just to select stock qty from stock table for the same location id and size id from sales table, like this:
Sales table:
------------------------------------
| loc_id | item_id | size_id | qty |
------------------------------------
| 5 | 11321 | 1 | 5 |
| 5 | 11321 | 2 | 8 |
| 5 | 11321 | 3 | 4 |
| 5 | 11321 | 2 | 1 |
Stock table:
------------------------------------
| loc_id | item_id | size_id | qty |
------------------------------------
| 5 | 11321 | 1 | 3 |
| 5 | 11321 | 2 | 7 |
| 5 | 11321 | 3 | 9 |
So the result after select should be like this:
------------------------------------------------------
| loc_id | item_id | size_id | sales_qty | stock_qty |
------------------------------------------------------
| 5 | 11321 | 1 | 5 | 3 |
| 5 | 11321 | 2 | 9 | 7 |
| 5 | 11321 | 3 | 4 | 9 |
Here's what I tried to do:
SELECT SUM(T1.qty) AS `salesQty`, SUM(T2.qty) AS `stockQty`, T1.size_id,
T1.loc_id
FROM sales T1
INNER JOIN stock T2 ON T2.item_id = T1.item_id AND T2.size_id = T1.size_id
WHERE T1.item_id = '11321'
AND T1.size_id IN (1,2,3)
AND T1.loc_id IN (5)
GROUP BY T1.size_id, T1.loc_id
But stock qty always wrong!

select
q1.loc_id
,q1.item_id
,q1.size_id
,sum(case when q1.Type='Sales' then q1.Qty else 0 end) as sales_qty
,sum(case when q1.Type='Stock' then q1.Qty else 0 end) as stock_qty
from (
select
T1.loc_id
,T1.item_id
,T1.size_id
,'Sales' as Type
,SUM(T1.qty) AS Qty
from sales T1
group by
T1.loc_id
,T1.item_id
,T1.size_id
union all
select
T2.loc_id
,T2.item_id
,T2.size_id
,'Stock' as Type
,SUM(T2.qty) AS Qty
from stock T2
group by
T2.loc_id
,T2.item_id
,T2.size_id) q1
group by
q1.loc_id
,q1.item_id
,q1.size_id

Related

How to join between two tables in SQL?

I have two tables
PC
----------------------------------
| PCID | PCName| IPAdd | CLnum |
----------------------------------
| 1 | PC1 |192.X.1| 1 |
| 2 | PC2 |192.x.2| 1 |
| 3 | PC3 |192.x.3| 1 |
----------------------------------
Date
----------------------------------
| DateID | Date | Time | PCID |
----------------------------------
| 1 |2/12/18| 17:05| 1 |
| 2 |2/12/18| 17:14| 1 |
| 3 |2/12/18| 17:18| 1 |
| 4 |2/12/18| 17:36| 1 |
| 5 |2/12/18| 18:23| 2 |
| 6 |2/12/18| 18:26| 2 |
| 7 |2/12/18| 18:28| 3 |
----------------------------------
SELECT t1.PCID, t1.PCName, t1.IPAdd, t1.CLnum, t2.date, t2.time
FROM pc t1 JOIN date t2 ON t2.PCID = t1.PCID
WHERE t2.PCID= t1.PCID and t2.date>=date order by time desc limit 1
I tried using the query above but the result I needed is like this:
example:
-------------------------------------------------
| PCID | PCName | IPAdd | CLnum | Date | Time |
-------------------------------------------------
| 1 | PC1 |192.x.1| 1 |02/12/18| 17:36|
| 2 | PC2 |192.x.2| 1 |02/12/18| 18:26|
| 3 | PC3 |192.x.3| 1 |02/12/18| 18:28|
-------------------------------------------------
What I'm trying to do is get the time in which each PC is last used on a selected date. How can I achieve this?
Seems you are looking for the max(time) for your values:
SELECT t1.pcid,
t1.pcname,
t1.ipadd,
t1.clnum,
t2.date,
Max(t2.time )
FROM pc t1 j oin date t2
ON t2.pcid = t1.pcid
WHERE t2.pcid= t1.pcid
AND t2.date>=date
GROUP BY t1.pcid,
t1.pcname,
t1.ipadd,
t1.clnum,
t2.date
ORDER BY t1.pcid

How to select only first matching value from another table in MySQL?

Here is my database schema:
Payment table:
+------------+--------+--------+---------------------+
| payment_id | tab_id | amount | created |
+------------+--------+--------+---------------------+
| 1 | 1 | 5 | 2017-05-22 12:14:27 |
| 2 | 2 | 10 | 2017-05-22 12:15:21 |
| 3 | 2 | 1 | 2017-05-22 13:11:14 |
+------------+--------+--------+---------------------+
Tab table:
+------------+----------------+
| tab_id | service_charge |
+------------+----------------+
| 1 | 1 |
| 2 | 3 |
+------------+----------------+
I need to calculate total amounts (amount + service_charge) per payment, but service_charge should be included only in first payment matching tab_id.
My current query:
SELECT
payment.payment_id,
(payment.amount + tab.service_charge) as total_amount,
payment.created
FROM payment
INNER JOIN tab
ON payment.tab_id = tab.tab_id;
Actual result:
As you can see below service_charge from tab_id = 2 included twice (payment_id = 2 and payment_id = 3).
+------------+-----------------+---------------------+
| payment_id | total_amount | created |
+------------+-----------------+---------------------+
| 1 | 6 | 2017-05-22 12:14:27 |
| 2 | 13 | 2017-05-22 12:15:21 |
| 3 | 4 | 2017-05-22 13:11:14 |
+------------+-----------------+---------------------+
Expected result:
total_amount should not include service_charge in payment_id = 3 as shown below.
+------------+-----------------+---------------------+
| payment_id | total_amount | created |
+------------+-----------------+---------------------+
| 1 | 6 | 2017-05-22 12:14:27 |
| 2 | 13 | 2017-05-22 12:15:21 |
| 3 | 1 | 2017-05-22 13:11:14 |
+------------+-----------------+---------------------+
You should determine which is the first payment matching the tab_id and then based on that info, decide if you want to use the service_charge or not:
SELECT
payment.payment_id,
payment.amount + if (payment.created=m.mintime, tab.service_charge, 0) as total_amount,
payment.created
FROM payment
INNER JOIN tab
ON payment.tab_id = tab.tab_id
JOIN (
SELECT tab_id, min(created) as 'mintime'
FROM payment
GROUP BY tab_id
) AS m on m.tab_id = payment.tab_id;

Get minimum from result with GROUP BY in MySQL

I have table it store hierarchy data in MySQL this table store stable relation but if each user less than 1000 buy removed and user User a lower level replace this is my code and work fine, after GROUP BY it contain all ancestor of descendant with compare then COUNT(*) AS level count level each user. This I have SQL code to compress data According to minimum buy for each user
+-------------+---------------+-------------+
| ancestor_id | descendant_id | path_length |
+-------------+---------------+-------------+
| 1 | 1 | 0 |
| 1 | 2 | 1 |
| 1 | 3 | 1 |
| 1 | 4 | 2 |
| 1 | 5 | 3 |
| 1 | 6 | 4 |
| 2 | 2 | 0 |
| 2 | 4 | 1 |
| 2 | 5 | 2 |
| 2 | 6 | 3 |
| 3 | 3 | 0 |
| 4 | 4 | 0 |
| 4 | 5 | 1 |
| 4 | 6 | 2 |
| 5 | 5 | 0 |
| 5 | 6 | 1 |
| 6 | 6 | 0 |
+-------------+---------------+-------------+
This is table buy
+--------+--------+
| userid | amount |
+--------+--------+
| 2 | 2000 |
| 4 | 6000 |
| 6 | 7000 |
| 1 | 7000 |
SQL code
SELECT a.*
FROM
( SELECT userid
FROM webineh_user_buys
GROUP BY userid
HAVING SUM(amount) >= 1000
) AS buys_d
JOIN
webineh_prefix_nodes_paths AS a
ON a.descendant_id = buys_d.userid
JOIN
(
SELECT userid
FROM webineh_user_buys
GROUP BY userid
HAVING SUM(amount) >= 1000
) AS buys_a on (a.ancestor_id = buys_a.userid )
JOIN
( SELECT descendant_id
, MAX(path_length) path_length
FROM webineh_prefix_nodes_paths
where a.ancestor_id = ancestor_id
GROUP
BY descendant_id
) b
ON b.descendant_id = a.descendant_id
AND b.path_length = a.path_length
GROUP BY a.descendant_id, a.ancestor_id
I need get max path_length where ancestor_id have At least 1000 amount buy but have error in where in subquery where a.ancestor_id = ancestor_id error code
1054 - Unknown column 'a.ancestor_id' in 'where clause'
I add SQLFidle demo.
You could use this query:
select m.userid as descendant,
p.ancestor_id,
p.path_length
from (
select b1.userid,
min(case when b2.amount >= 1000
then p.path_length
end) as path_length
from (select userid, sum(amount) amount
from webineh_user_buys
group by userid
having sum(amount) >= 1000
) as b1
left join webineh_prefix_nodes_paths p
on p.descendant_id = b1.userid
and p.path_length > 0
left join (select userid, sum(amount) amount
from webineh_user_buys
group by userid) as b2
on p.ancestor_id = b2.userid
group by b1.userid
) as m
left join webineh_prefix_nodes_paths p
on p.descendant_id = m.userid
and p.path_length = m.path_length
order by m.userid
Output for sample data in the question:
| userid | ancestor_id | path_length |
|--------|-------------|-------------|
| 1 | (null) | (null) |
| 2 | 1 | 1 |
| 4 | 2 | 1 |
| 6 | 4 | 2 |
SQL fiddle

group Items by column and order by other column

I have table as below , I want to take latest rating for the client
basically user whenever updates rating, count will be incremented and a entry will be made in table. Table goes as below
-----------------------------------------------------
|_id| name | client_id | user_id | rating | count |
-----------------------------------------------------
|1 | Four | 1 | 1 | 4 | 1 |
|2 | three | 1 | 1 | 3 | 2 |
|3 | two | 1 | 1 | 2 | 3 |
|4 | five | 1 | 1 | 5 | 4 |
|5 | two | 1 | 2 | 2 | 1 |
|6 | three | 1 | 2 | 3 | 2 |
|7 | two | 2 | 1 | 2 | 1 |
|8 | three | 2 | 1 | 3 | 2 |
-----------------------------------------------------
For rating of client_id 1 I want out put like
-----------------------------------------------------
|_id| name | client_id | user_id | rating | count |
-----------------------------------------------------
|4 | five | 1 | 1 | 5 | 4 |
|6 | three | 1 | 2 | 3 | 2 |
-----------------------------------------------------
so far I tried SELECT * FROM test
where client_id = 1 group by client_id order by count desc;
but not getting expected result, any help??
You can use left join on the same table as
select t1.* from test t1
left join test t2 on t1.user_id = t2.user_id
and t1.client_id = t2.client_id
and t1._id < t2._id
where
t2._id is null
and t1.client_id = 1
order by t1.`count` desc;
Using un-correlated subquery you may do as
select t1.* from test t1
join (
select max(_id) as _id,
client_id,
user_id
from test
where client_id = 1
group by client_id,user_id
)t2
on t1._id = t2._id
and t1.client_id = t2.client_id
order by t1.`count` desc;
UPDATE : From the comment how to join another table into above , for this here is an example
mysql> select * from users ;
+------+------+
| _id | name |
+------+------+
| 1 | AAA |
| 2 | BBB |
+------+------+
2 rows in set (0.00 sec)
mysql> select * from test ;
+------+-------+-----------+---------+--------+-------+
| _id | name | client_id | user_id | rating | count |
+------+-------+-----------+---------+--------+-------+
| 1 | four | 1 | 1 | 4 | 1 |
| 2 | three | 1 | 1 | 3 | 2 |
| 3 | two | 1 | 1 | 2 | 3 |
| 4 | five | 1 | 1 | 5 | 4 |
| 5 | two | 1 | 2 | 2 | 1 |
| 6 | three | 1 | 2 | 3 | 2 |
| 7 | two | 2 | 1 | 2 | 1 |
| 8 | three | 2 | 1 | 3 | 2 |
+------+-------+-----------+---------+--------+-------+
select t1.*,u.name from test t1
join users u on u._id = t1.user_id
left join test t2 on t1.user_id = t2.user_id
and t1.client_id = t2.client_id
and t1._id < t2._id
where
t2._id is null
and t1.client_id = 1
order by t1.`count` desc;
Will give you
+------+-------+-----------+---------+--------+-------+------+
| _id | name | client_id | user_id | rating | count | name |
+------+-------+-----------+---------+--------+-------+------+
| 4 | five | 1 | 1 | 5 | 4 | AAA |
| 6 | three | 1 | 2 | 3 | 2 | BBB |
+------+-------+-----------+---------+--------+-------+------+
Note that the join to users table is inner join and this will require all the user to be preset in users table which are in test table
If some users are missing in the users table then use left join this will have null values for the data selected from users table.
You may try something like
select _id, name, client_id, user_id, rating, max(count)
from clients
group by client_id
Try it
SELECT * FROM test
where client_id = 1
group by user_id
order by count desc

Updating a column after deleting a row

I'm learning to use MySQL and therefore I'm trying to make a simple inventory management.
If I delete an invoice how can I not just delete from the invoice table and from the invoiceItemTable as well but update the "Amount" column with the subtraction value at the right store in my Inventory Table? Since if I want to do
SUM(inventory.amount) - SUM(SELECT amount FROM InvoiceItemTable WHERE invoice_id = 1
GROUP BY Product_id)
this will fail because subqueries have more than 1 rows. Below you can see my database structure.
InvoceTable
+---+----------------+----------+
|ID | invoice_number | Store_id |
+---+----------------+----------+
| 1 | 1234 | 1 |
+---+----------------+----------+
InvoiceItemTable
+---+----------------+------------+---------+
|ID | invoice_id | Product_id | Amount |
+---+----------------+------------+---------+
| 1 | 1 | 1 | 5 |
+---+----------------+------------+---------+
| 2 | 1 | 1 | 5 |
+---+----------------+------------+---------+
| 3 | 2 | 1 | 10 |
+---+----------------+------------+---------+
Inventory
+---+----------------+---------+----------+
|ID | Product_id | Amount | Store_id |
+---+----------------+---------+----------+
| 1 | 1 | 15 | 1 |
+---+----------------+---------+----------+
| 2 | 2 | 15 | 1 |
+---+----------------+---------+----------+
| 3 | 2 | 15 | 2 |
+---+----------------+---------+----------+
UPDATE:
Expectation after the queries:
InvoceTable
+---+----------------+----------+
|ID | invoice_number | Store_id |
+---+----------------+----------+
| | | |
+---+----------------+----------+
InvoiceItemTable
+---+----------------+------------+---------+
|ID | invoice_id | Product_id | Amount |
+---+----------------+------------+---------+
| 3 | 2 | 1 | 10 |
+---+----------------+------------+---------+
Inventory
+---+----------------+---------+----------+
|ID | Product_id | Amount | Store_id |
+---+----------------+---------+----------+
| 1 | 1 | 5 | 1 |
+---+----------------+---------+----------+
| 2 | 2 | 5 | 1 |
+---+----------------+---------+----------+
| 3 | 2 | 15 | 2 |
+---+----------------+---------+----------+
you'd need to use sum inside the subquery:
select SUM(inventory.amount) - (SELECT SUM(amount) FROM InvoiceItemTable WHERE invoice_id = 1 GROUP BY Product_id)
from inventory
check sqlfiddle for your database scheme and the running query.
this query should decrease the Inventory table's amount column according to invoiceitemtable table:
update Inventory set Amount = Amount - (SELECT SUM(amount) FROM InvoiceItemTable WHERE invoice_id = 1 AND Product_id = Inventory.Product_id GROUP BY Product_id)
SUM(inventory.amount) - (SELECT SUM(amount) FROM InvoiceItemTable WHERE invoice_id = 1 GROUP BY Product_id)