GROUP sum BY two tables by joining - mysql

I'm trying to write a SQL query that will correctly group sales items sold_qyt and sub-total-price together as per product's category so I can show this on the printable invoice that product from Jelly Sheet = 4 at a rate of 62 subtotal for this category product is 248(4 * 62 = 248). but when I try to run the below-mentioned query it shows out-put as 12 but I want subtotal and sold_qyt segregated base on category.
I have tried to run different queries just one query gives the output which is mentioned below and this is for just the sum of all sold_qyt. DB example is also shown below
DB Example: (For better understanding)
Table # 1:
Category
ID | code | name
1 | 1 | jelly sheet
2 | 2 | 9D Glass
3 | 3 | Polished Glass
Table # 2:
Product:
ID | code | name | cost | category_id | price
1 | 1 | IP11JS | 50 | 1 | 62
2 | 2 | IP12JS | 50 | 1 | 62
3 | 3 | IP119D | 40 | 2 | 55
4 | 4 | IP129D | 40 | 2 | 55
5 | 5 | IP11PG | 18 | 3 | 25
6 | 6 | IP12PG | 18 | 3 | 25
Table # 3:
sale_items:
ID | sale_id | product_id | product_code | product_name | unit_price | sold_qyt | subtotal |
1 | 1 | 1 | 1 | IP11JS | 62 | 2 | 124 |
2 | 1 | 2 | 2 | IP12JS | 62 | 2 | 124 |
3 | 1 | 3 | 3 | IP119D | 55 | 2 | 110 |
4 | 1 | 4 | 4 | IP129D | 55 | 2 | 110 |
5 | 1 | 5 | 5 | IP11PG | 25 | 2 | 50 |
6 | 1 | 6 | 6 | IP12PG | 25 | 2 | 50 |
7 | 2 | 7 | 1 | IP11JS | 62 | 2 | 124 |
8 | 2 | 8 | 2 | IP12JS | 62 | 2 | 124 |
9 | 2 | 9 | 3 | IP119D | 55 | 2 | 110 |
10 | 2 | 10 | 4 | IP129D | 55 | 2 | 110 |
11 | 2 | 11 | 5 | IP11PG | 25 | 2 | 50 |
12 | 2 | 12 | 6 | IP12PG | 25 | 2 | 50 |
SQL Query which is run by me:
SELECT sale_id,
SUM(sold_qyt) AS sold_qyt
FROM sale_items
GROUP BY sale_id
kindly help me with this difficulty thanks in advance
Update: 1-21-2021
i execute new query
SELECT (sma_sale_items.sale_id, sma_categories.code AS sma_products.category_id, sma_products.code AS sma_sale_items.product_code,)
SUM(sold_qyt) AS sold_qyt
SUM(subtotal) AS subtotal
FROM sma_sale_items
LEFT JOIN sma_products ON sma_products.id=sma_sale_items.product_id
LEFT JOIN sma_categories ON sma_categories.code=sma_products.category_id
GROUP BY sma_sale_items.sale_id
ORDER BY sma_categories
but no luck :(
I want the output like this:
Expected OUT PUT:
ID | sale_id | category_name | sold_qyt | subtotal |
1 | 1 | Jelly Sheet | 4 | 248 |
2 | 1 | 9D Glass | 4 | 220 |
3 | 1 | Polished Glass | 4 | 100 |
4 | 2 | Jelly Sheet | 4 | 248 |
5 | 2 | 9D Glass | 4 | 220 |
6 | 2 | Polished Glass | 4 | 100 |

The ID column in your expected result set is very misleading - it appears to be just new ID value for the output result set rather than any of the ID values from the source tables.
If it is important for you then you can use this query:
SELECT ROW_NUMBER() OVER (ORDER BY sale_id, category_id),
sale_id,
category_name,
sold_qty,
subtotal
FROM (
SELECT c.ID as category_id,
si.sale_id,
c.[name] as category_name,
SUM(si.sold_qty) as sold_qty,
SUM(si.subtotal) as subtotal
FROM sale_items si
JOIN product p ON p.ID = si.product_code
JOIN category c ON c.ID = p.category_id
GROUP BY c.ID,
si.sale_id,
c.[name]
) r
If it is not relevant and you only want the sale_id, category_name and the totals then simplify it to:
SELECT si.sale_id,
c.[name] as category_name,
SUM(si.sold_qty) as sold_qty,
SUM(si.subtotal) as subtotal
FROM sale_items si
JOIN product p ON p.ID = si.product_code
JOIN category c ON c.ID = p.category_id
GROUP BY si.sale_id,
c.[name]
ORDER BY sale_id, category_name

Related

Extracting data from table with results from different search

I am trying to extract data from tables with the results from a previous search. I am not really familiar with database query's and have made one that will crash my computer from drawing too much memory.
This data is coming from a board tester and I want certain information.
How many boards were ran during a given period
How many failed
All the failure data for those boards EDIT: This is the one I need to figure out. See Edit at bottom.
The first time a board is ran it creates a record in the Board table
+----------+-------+-----+
| Board_id | Board | rev |
+----------+-------+-----+
| 1 | 1234 | 1 |
| 2 | 1234 | 1 |
| 3 | 1235 | 2 |
| 4 | 5869 | 15 |
+----------+-------+-----+
Each time the board is ran it creates a Test record
+----------+----------+---------+---------------------+
| Test_id | Board_id | Operator| Date_Time |
+----------+----------+---------+---------------------+
| 34 | 1 | 1 | 2017-08-02 09:13:34 |
| 35 | 1 | 1 | 2017-08-02 09:13:36 |
| 36 | 1 | 1 | 2017-08-02 09:13:39 |
| 37 | 2 | 1 | 2017-08-02 09:14:10 |
| 38 | 3 | 1 | 2017-08-02 09:16:24 |
| 39 | 3 | 2 | 2017-08-03 10:40:45 |
| 40 | 4 | 2 | 2017-08-03 10:43:34 |
+----------+----------+---------+---------------------+
...and Results are stored in Results
+-----------+---------+--------+-------------+-------------+
| Result_id | Test_id | Result | Upper_Limit | Lower_Limit |
+-----------+---------+----------------------+-------------+
| 40 | 34 | 2 | 4 | 1 |
| 41 | 34 | 3 | 4 | 1 |
| 42 | 34 | 4 | 4 | 1 |
| 43 | 34 | 0 | 4 | 1 |
| 44 | 35 | 2 | 4 | 1 |
| 45 | 35 | 3 | 4 | 1 |
| 46 | 35 | 4 | 4 | 1 |
| 47 | 35 | 0 | 4 | 1 |
| 48 | 36 | 2 | 4 | 1 |
| 49 | 36 | 3 | 4 | 1 |
| 50 | 36 | 4 | 4 | 1 |
| 51 | 36 | 2 | 4 | 1 |
| 52 | 37 | 2 | 4 | 1 |
| 53 | 37 | 3 | 4 | 1 |
| 54 | 37 | 4 | 4 | 1 |
| 55 | 37 | 2 | 4 | 1 |
| 56 | 38 | 2 | 4 | 1 |
| 57 | 38 | 3 | 4 | 1 |
| 58 | 38 | 4 | 4 | 1 |
| 59 | 38 | 5 | 4 | 1 |
| 60 | 39 | 2 | 4 | 1 |
| 61 | 39 | 3 | 4 | 1 |
| 62 | 39 | 4 | 4 | 1 |
| 63 | 39 | 5 | 4 | 1 |
| 64 | 40 | 2 | 4 | 1 |
| 65 | 40 | 3 | 4 | 1 |
| 66 | 40 | 4 | 4 | 1 |
| 67 | 40 | 3 | 4 | 1 |
+-----------+---------+--------+-------------+-------------+
To get the number of boards, and Board_ID, ran during a given period I query.
SELECT a.Board_ID FROM
Tests a, Results b
WHERE a.Date_Time>='2017-08-02' AND a.Date_Time<'2017-08-03' and
a.Test_ID = b.Test_ID
group by a.Board_ID
To get all associated test to those Board_ID's I query.
SELECT * from
Tests x, (
SELECT a.Board_ID FROM
Tests a, Results b
WHERE a.Date_Time>='2017-08-02' AND a.Date_Time<'2017-08-03' and
a.Test_ID = b.Test_ID
group by a.Board_ID
) y
where x.Board_ID = y.Board_ID
This gives me the correct results, but the query seems off, but when I try to get the failed results from the query above is when I have the most trouble.
SELECT d.Test_ID FROM
Boards a, Tests b, (
SELECT x.Test_ID, x.Board_ID, x.Operator, x.Date_Time from
Tests x, (
SELECT a.Board_ID FROM
Tests a, Results b
WHERE a.Date_Time>='2017-08-02' AND a.Date_Time<'2017-08-03' and
a.Test_ID = b.Test_ID
group by a.Board_ID
) y
)d
WHERE d.Test_ID = b.Test_ID and
b.Result not between Lower_Limit and Upper_Limit
EDIT:
If you look at the Test table I created you will see that board_id 3 got tested twice and on two different days. I need to see the boards that we ran on a given day, this example 2017-08-02, and all associated records to those boards. So since Board_ID #3 was ran on 2 days, and was ran on the day in question, I would need that record included in my query.
My Solution
SELECT * FROM
(
SELECT x.Test_ID, x.Board_ID, x.Operator, x.Date_Time from
Test x, (
SELECT a.Board_ID FROM
Test a
join Results b on a.Test_ID = b.Test_ID
WHERE a.Date_Time>='2017-08-11' AND a.Date_Time<'2017-08-12'
group by a.Board_ID
) y
where x.Board_ID = y.Board_ID
)d
join Boards a on a.Board_ID = d.Board_ID
join Results b on b.Test_ID = d.Test_ID
join Test_Names c on c.Test_Name_ID = b.Test_Name_ID --Table Not shown
WHERE
b.result not between Lower_Limit and Upper_Limit
From this you see I have 3 nested searches into 1. With the 3 individual searches I get all the data I need to parse the information I want. Next will be to find a way to query the database for what I need instead of parsing.
I think you're overthinking this. You don't need all the inline views. Here's how I would write it using ANSI Joins (like #CptMisery suggested in the comments)
SELECT d.test_id, b.board, b.board_rev, r.result_id, r.result -- and whatever else you need.
from tests t
join results r on t.test_id = r.test_id
join boards b on t.board_id = b.board_id
where t.Date_Time>='2017-08-02' AND t.Date_Time<'2017-08-03'
and r.result >Lower_Limit -- or >=
and r.result < Upper_Limit -- or <=, if it can be the limit value
JOIN all the tables based on their relationships (Foreign Key to Primary Key), choose your filters in the where clause, and choose the columns to "project" with Select.
SELECT d.Test_ID FROM
Boards a, Tests b, ( SELECT x.Test_ID,
x.Board_ID,
x.Operator,
x.Date_Time
from Tests x,
(SELECT a.Board_ID
FROM Tests a, Results b
WHERE a.Date_Time>='2017-08-02'
AND a.Date_Time<'2017-08-03'
and a.Test_ID = b.Test_ID
group by a.Board_ID
) y
)d
WHERE d.Test_ID = d.Test_ID
and b.Result >= Lower_Limit
and b. Result <=Upper_Limit

Subtract two columns of different tables with different number of rows

How can I write a single query that will give me SUM(Entrance.quantity) - SUM(Buying.quantity) group by product_id.
The problem is in rows that not exist in the first or second table. Is possible to do this?
Entrance:
+---+--------------+---------+
| id | product_id | quantity|
+---+--------------+---------+
| 1 | 234 | 15 |
| 2 | 234 | 35 |
| 3 | 237 | 12 |
| 4 | 237 | 18 |
| 5 | 101 | 10 |
| 6 | 150 | 12 |
+---+--------------+---------+
Buying:
+---+------------+-------------+
| id | product_id | quantity|
+---+------------+-------------+
| 1 | 234 | 10 |
| 2 | 234 | 20 |
| 3 | 237 | 10 |
| 4 | 237 | 10 |
| 5 | 120 | 15 |
+---+------------+------------+
Desired result:
+--------------+-----------------------+
| product_id | quantity_balance |
+--------------+-----------------------+
| 234 | 20 |
| 237 | 10 |
| 101 | 10 |
| 150 | 12 |
| 120 | -15 |
+--------------+-----------------------+
This is tricky, because products could be in one table but not the other. One method uses union all and group by:
select product_id, sum(quantity)
from ((select e.product_id, quantity
from entrance e
) union all
(select b.product_id, - b.quantity
from buying b
)
) eb
group by product_id;
SELECT product_id ,
( Tmp1.enterquantity - Tmp2.buyquantity ) AS Quantity_balance
FROM entrance e1
CROSS APPLY ( SELECT SUM(quantity) AS enterquantity
FROM Entrance e2
WHERE e1.product_id = e2.product_id
) Tmp1
CROSS APPLY ( SELECT SUM(quantity) AS buyquantity
FROM Buying b2
WHERE e1.product_id = b2.product_id
) Tmp2
GROUP BY Product_id,( Tmp1.enterquantity - Tmp2.buyquantity )

Select the entire row of the lowest price for distinct product

I have the below table about products:
| id | name | product_id | price | seller_id | discount_id |
--------------------------------------------------------------
| 1 | phone | 11 | 400 | 7 | 19 |
| 2 | cpu | 78 | 120 | 33 | 4 |
| 3 | phone | 11 | 380 | 8 | 22 |
| 4 | phone | 11 | 460 | 5 | 19 |
| 5 | memory | 80 | 45 | 12 | 16 |
| 6 | router | 98 | 115 | 7 | 16 |
| 7 | cpu | 78 | 115 | 33 | 66 |
I need to select all the columns of distinct product_id with the lowest price. Also to ORDER the result by price ASC. For this example:
| id | name | product_id | price | seller_id | discount_id |
--------------------------------------------------------------
| 5 | memory | 80 | 45 | 12 | 16 |
| 6 | router | 98 | 115 | 7 | 16 |
| 7 | cpu | 78 | 115 | 33 | 66 |
| 3 | phone | 11 | 380 | 8 | 22 |
I have no problems doing this using GROUP BY product_id and min(price) but I also need other columns (seller_id & discount_id)
MySQL version: 5.7.17
sql_mode=only_full_group_by
Table is temporary (ENGINE=MEMORY) and can't JOIN multiple times
How can I produce the result above from MySQL?
Add a subquery with the min price and join on min price and product.
SELECT id, name,product_id,price,seller_id,discount_id FROM t
JOIN
(SELECT tt.product_id,MIN(tt.price) minp FROM t as tt
GROUP BY tt.product_id)x
ON x.product_id=t.product_id AND x.price = t.price
Another option with LIMIT
SELECT * FROM T WHERE EXISTS
(SELECT 1 FROM T as TT ORDER BY TT.price ASC LIMIT 1
WHERE t.id= TT.id)
Given that the MEMORY engine is so restricting go the caveman way
SELECT SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY price),',',1),
SUBSTRING_INDEX(GROUP_CONCAT(name ORDER BY price),',',1),
product_id,MIN(price),
SUBSTRING_INDEX(GROUP_CONCAT(seller_id ORDER BY price),',',1),
SUBSTRING_INDEX(GROUP_CONCAT(discount_id ORDER BY price),',',1) FROM t
GROUP BY product_id
You can join the table with itself (on product_id). As a join-condition add left.price > right.price - and then choose the rows, where right.price is null, because for that join, there is no lower right price, meaning the one you have left is the lowest:
SELECT l.id, l.name, l.product_id, l.price, l.seller_id, l.discount_id
FROM
products l
LEFT JOIN
products r
on
l.product_id = r.product_id AND l.price > r.price
WHERE
isnull (r.price) -- that means: no cheaper price for this position.
intermediate result (SELECT * no WHERE) would look like (shortened):
| l.id | l.name | l.product_id | l.price | r.id | r.name | r.product_id | r.price
| 3 | phone | 11 | 380 | null | null | null | null
| 4 | phone | 11 | 460 | 3 | phone | 3 | 380
Side node: For very large datasets there might be performance-issues, because every additional line of a component would add multiple result rows. i.e. consider another phone:
| l.id | l.name | l.product_id | l.price | r.id | r.name | r.product_id | r.price
| 3 | phone | 11 | 380 | null | null | null | null
| 4 | phone | 11 | 460 | 3 | phone | 3 | 380
| 5 | phone | 11 | 500 | 3 | phone | 3 | 380
| 5 | phone | 11 | 500 | 4 | phone | 3 | 460
So, if you want to get the lowest price in the past 60 days with daily changes, that will be a huge amount of rows just for "that"... (Actually 60+59+58+...+2+1 I think, cause the most expensive price will produce 59 comparision rows and so on)

SQL Query to Sort the result according to maximum common results

I have a problem in making SQL query. I am making a small Search Engine in which the word to page mapping or indexes are kept like this.
Sorry I wasn't able to post images here so I tried writing the output like this.
+---------+---------+-----------+--------+
| word_id | page_id | frequency | degree |
+---------+---------+-----------+--------+
| 2331 | 29 | 2 | 1 |
| 2332 | 29 | 7 | 1 |
| 2333 | 29 | 4 | 1 |
| 2334 | 29 | 1 | 1 |
| 2335 | 29 | 1 | 1 |
| 2336 | 29 | 1 | 1 |
| 2337 | 29 | 2 | 1 |
| 2338 | 29 | 7 | 1 |
| 2343 | 29 | 1 | 3 |
| 2344 | 29 | 1 | 3 |
......
......
...... and so on.
Word_id points to Words present in other table and page_id points to URLs present in other table.
Now Suppose I want to search "Rapid 3D Prototyping Services". I brought the union of results corresponding to individual words by query ->
select * from words_detail where word_id=2353 or word_id=2364 or word_id=2709 or word_id=2710;
In above query the word_ids corresponds to the 4 words in the search query and the results are as below.
Union of page_id corresponding to individual words...
mysql>
select * from words_detail where word_id=2353 or word_id=2364 or word_id=2709 or word_id=2710;
+---------+---------+-----------+--------+
| word_id | page_id | frequency | degree |
+---------+---------+-----------+--------+
| 2353 | 29 | 2 | 4 |
| 2353 | 33 | 2 | 2 |
| 2353 | 36 | 5 | 9 |
| 2353 | 40 | 1 | 4 |
| 2353 | 41 | 1 | 9 |
| 2353 | 45 | 4 | 9 |
| 2353 | 47 | 2 | 9 |
| 2353 | 49 | 4 | 9 |
| 2353 | 52 | 1 | 4 |
| 2353 | 53 | 1 | 9 |
| 2353 | 66 | 2 | 9 |
| 2364 | 29 | 1 | 4 |
| 2364 | 34 | 1 | 4 |
| 2364 | 36 | 9 | 2 |
| 2709 | 36 | 1 | 9 |
| 2710 | 36 | 1 | 9 |
+---------+---------+-----------+--------+
16 rows in set (0.00 sec)
But I want the result to be sorted according to maximum match. The earlier result should be where all 4 words match, next result should be with 3 match and so on. In other words earlier results should have those page_id which are common to 4 word_ids, next should be those which are common in 3 words_ids and so on.
I checked here but this is not working in my case because in my case OR conditions are not matched in a single row.
How can such a query can be designed?
Use the occurence of you page_id as your matching count and then order by it.
select * from words_detail A
inner join
(SELECT PAGE_ID
, COUNT(PAGE_ID) matchCount
from words_detail
where word_id=2353 or word_id=2364 or word_id=2709 or word_id=2710
group by PAGE_ID) B
on A.PAGE_ID=B.PAGE_ID
where word_id=2353 or word_id=2364 or word_id=2709 or word_id=2710
order by matchCount desc
Try this
select p.*
from words_detail p
, (select word_id, count(1) as count
from words_detail where
word_id in (2353,2364,2709,2710) group by word_id) t
where p.word_id = t.word_id
order by t.count desc;
You can do a subquery to get the number of apperances for each page. Then you have to join the subquery with your table and you will be able to order the results by the number of page appearances.
Your final query should look like this:
SELECT *
FROM words_detail,
(
SELECT page_id,
COUNT(*) AS npages
FROM words_detail
WHERE word_id IN (2353, 2364, 2709, 2710)
GROUP BY page_id
) AS matches
WHERE words_detail.page_id = matches.page_id
AND word_id IN (2353, 2364, 2709, 2710)
ORDER BY matches.npages DESC

Get distinct records of two columns in a join with 6 columns

I have two MySQL tables SPONSORSHIPS and EVENTS. I want to display a list of SPONSORSHIPS sorted by the category of the events they sponsor, but to only show a sponsorship once under each event. Sample join table:
SPONSORSHIPS
sponsorhipid | sponsorid | eventid | date |
-------------|-----------|---------|------------|
1 | 3 | 20 | 06/01/2013 |
2 | 2 | 20 | 06/02/2013 |
3 | 3 | 20 | 06/03/2013 |
4 | 2 | 21 | 06/04/2013 |
EVENTS
eventid | name | premium |
--------|-----------|------------|
20 | Lunch | 0 |
21 | Dinner | 1 |
What I'd like to have as a result of the JOIN is:
sponsorhipid | sponsorid | eventid | date | name | premium |
-------------|-----------|---------|------------|---------| ---------|
1 | 3 | 20 | 06/01/2013 | Lunch | 0 |
2 | 2 | 20 | 06/02/2013 | Lunch | 0 |
4 | 2 | 21 | 06/04/2013 | Dinner | 1 |
I tried DISTINCT and GROUP BY but these collapse the events so if sponsor #2 sponsors two different events they'd still be shown only once. How can I achieve this? Here is my last SQL query:
SELECT DISTINCT (sponsorships.sponsorshipid), sponsorships.*, events.*
FROM events
INNER JOIN sponsorships
ON events.eventid = sponsorships.eventid
Thanks so much for any pointers!
You need to use nested sub-queries like this:
SELECT s.sponsorhipid, s.sponsorid, s.eventid, s.date
,e.name, e.premium
FROM EVENTS e
JOIN
(
SELECT s1.* FROM SPONSORSHIPS s1
JOIN
(
SELECT sponsorid, MIN(Date) As minDate
FROM SPONSORSHIPS
GROUP BY eventid,sponsorid
) s2
ON s1.sponsorid = s2.sponsorid
AND s1.date = s2.minDate
) s
ON e.eventid = s.eventid;
Output:
| SPONSORHIPID | SPONSORID | EVENTID | DATE | NAME | PREMIUM |
|--------------|-----------|---------|------------|--------|---------|
| 1 | 3 | 20 | 06/01/2013 | Lunch | 0 |
| 2 | 2 | 20 | 06/02/2013 | Lunch | 0 |
| 4 | 2 | 21 | 06/04/2013 | Dinner | 1 |
See this SQLFiddle