I am trying to fetch remaining quantity of books with following approach
stock = total+(receive-Issued);
Table book_qnt - lists of book Quantiy
id | book | qnt
=======================
1 | 1 | 20
2 | 2 | 12
Table book - lists of Book
id | ttl
===========
1 | Social Experiment
2 | Evolution of Culture
Table book_trns - lists of book transcation
id | bk | std | iss | rcv | dte
==========================================
1 | 2 | 1 | 6 | 0 | 2019-04-11
2 | 2 | 2 | 4 | 0 | 2019-04-05
It is fine for only those books which has receive and issued values.
In DB language, it is displaying result of those books which book_trans.rcv and book_trans.iss is not NULL
SELECT
book.id AS book,
book_qnt.qnt+((SUM(book_trans.rcv))-(SUM(book_trans.iss))) AS stock,
Result
book| stock
===========
1 | NULL
2 | 2
Now I am try to fetch result as following, if book_trans.rcv and book_trans.iss is NULL, then it should fetch total qnt from book_qnt
Desired Result
book| stock
===========
1 | 20 // id 1's book_trans.rcv and book_trans.iss is NULL, so it should show total qnt
2 | 2 // id 2's book_trans.rcv and book_trans.iss is not NULL, so it is calculating
What I do if book_trans.rcv and book_trans.iss row is Null, then assign value as 0.
SELECT
book.id AS book,
book_qnt.qnt+((IFNULL(0, SUM(book_trans.rcv)))-(IFNULL(0, SUM(book_trans.iss)))) AS stock,
But Result (calculation doesn't work)
book| qnt
===========
1 | 20
2 | 12
Full MySQL
SELECT
book_qnt.qnt+((IFNULL(0, SUM(book_trans.rcv)))-(IFNULL(0, SUM(book_trans.iss)))) AS stock,
lib_bk.id,
lib_bk.ttl
FROM
book
JOIN
book_qnt ON book_qnt.book=book.id
LEFT JOIN
book_trans ON book_trans.bk=book.id
GROUP BY book.id
Your 0 replacement in the null test is the wrong way round. Try this
SELECT
book_qnt.qnt , SUM(book_trns.rcv), SUM(book_trns.iss),
((IFNULL(SUM(book_trns.rcv),0))-(IFNULL(SUM(book_trns.iss),0))),
book_qnt.qnt+((IFNULL(SUM(book_trns.rcv),0))-(IFNULL(SUM(book_trns.iss),0))) AS stock,
book.id,
book.ttl
FROM
book
JOIN
book_qnt ON book_qnt.book=book.id
LEFT JOIN
book_trns ON book_trns.bk=book.id
GROUP BY book.id;
+------+--------------------+--------------------+-----------------------------------------------------------------+-------+------+----------------------+
| qnt | SUM(book_trns.rcv) | SUM(book_trns.iss) | ((IFNULL(SUM(book_trns.rcv),0))-(IFNULL(SUM(book_trns.iss),0))) | stock | id | ttl |
+------+--------------------+--------------------+-----------------------------------------------------------------+-------+------+----------------------+
| 20 | NULL | NULL | 0 | 20 | 1 | Social Experiment |
| 12 | 0 | 10 | -10 | 2 | 2 | Evolution of Culture |
+------+--------------------+--------------------+-----------------------------------------------------------------+-------+------+----------------------+
2 rows in set (0.00 sec)
And do try to keep your table names consistent with the query.
Related
I have a system which stores peoples outfits. Each outfit contains 1 to many items.
Thus my tables are like this
outfits
+-----------+--------+
| outfit_id | cus_id |
+-----------+--------+
| 1 | 5 |
| 2 | 92 |
+-----------+--------+
items
+---------+-------+-------+
| item_id | name | sku |
+---------+-------+-------+
| 1 | hat | 1111 |
| 2 | pants | 2222 |
| 3 | shirt | 3333 |
| 4 | shoes | 4444 |
+---------+-------+-------+
items_in_outfit
+--------+-----------+---------+
| ino_id | outfit_id | item_id |
+--------+-----------+---------+
| 1 | 1 | 3 |
| 2 | 1 | 2 |
| 3 | 1 | 4 |
| 4 | 2 | 1 |
| 4 | 2 | 3 |
+--------+-----------+---------+
I am given this information:
cus_id=92 wants to create another outfit with the sku's 1111 and 3333
However, this is a duplicate of outfit_id=2. So I want mysql to return me the outfit_id of 2. If its not a duplicate, return nothing. It only counts as a duplicate if the same cus_id is trying to make an outfit which has the exact same sku's already.
If cus_id=5 wants to create another outfit with the sku's 1111 and 3333. It should return nothing (as its not a duplicate) because cus_id=5 doesn't have an outfit with just 1111 and 3333
SELECT o.outfit_id FROM
outfits o JOIN
items_in_outfit iio
ON o.outfit_id = iio.outfit_id JOIN
items i
ON iio.item_id = i.item_id
WHERE cus_id = 92 AND ...
This may help you achieve what you are looking for :
select
cus_id
from(
select
cus_id,
group_concat(sku order by sku asc) as items
from outfits o
join items_in_outfit iio on o.outfit_id = iio.outfit_id
join items i on iio.item_id = i.item_id
group by cus_id
) T
where items = '1111,3333'
SEE DEMO HERE
EDIT : As an outfit can't contain more than 1 instance of the same item, this solution may be better for you as you don't have to order the sku id in your php before :
select
o.outfit_id
from
outfits o
join items_in_outfit iio on o.outfit_id = iio.outfit_id
join items i on iio.item_id = i.item_id
where sku IN (1111, 3333)
group by o.outfit_id having COUNT(*) = 2
SEE SECOND DEMO HERE
Why SUM() counts row twice and displaying double of actual result in here ?
Here I m trying to count total rows of status that has 0 value from the inv_id table of each student (inv_id.s_id) .
it has to show 4 based on the row number in inv_lst table but here it is showing 8.
If fee.id is GROUP_BY then it shows actual SUM but same student id starts to duplicate.
Please see fiddle - SQL Fiddle
Database Structure
class
id | ttl
===========
1 | One
2 | Two
section
id | ttl
===========
1 | A
2 | B
fee
id | ttl
===============
1 | Annual
2 | Monthly
student
id | ttl | cls | sec
===========================
1 | John| 1 | 1
2 | Paul| 1 | 1
3 | Rina| 2 | 1
sec_fee
id | c_id| s_id| f_id| fee
===================================
1 | 1 | 1 | 1 | 1000
2 | 2 | 1 | 2 | 560
inv_id
id | s_id| ft_id | status
==================================
1 | 1 | 1 | 0
2 | 1 | 2 | 0
3 | 1 | 3 | 0
4 | 1 | 4 | 0
Mysql
SELECT
student.id, student.ttl AS stdt,
cls.ttl AS cls,
sec.ttl AS sec,
GROUP_CONCAT(DISTINCT fee.id, '.', fee.ttl, '-', sec_fee.fee,'<br/>' ORDER BY sec_fee.f_id) AS amnt,
SUM(inv_id.status=0) AS upad,
SUM(inv_id.status=1) AS pad
FROM
student
JOIN
cls ON cls.id=student.cls
LEFT JOIN
sec ON sec.id=student.sec
LEFT JOIN
inv_id ON inv_id.s_id = student.id
LEFT JOIN
sec_fee ON sec_fee.c_id = student.cls
LEFT JOIN
fee ON fee.id = sec_fee.f_id
WHERE
cls.id = 1
I have basically have two tables:
1) billingcharges : here we store id of a restaurant (restid) , charge id (chargeid), chargetime(timeinmillis when the charge occurred),chargeamount(int amount of the actual charge).charge id is a foreign key to the billingchargedetails table.
2) billingchargedetails: here we store the details of all the possible charges. chargeid(primary key int), chargename (name of the charge), perdaycost (cost per day of the charge)
What i expect:
a summary report of totalamount of charge for each charge for each restaurant.
The current entries inside the tables are:
select * from billingcharges;
+--------+----------+---------------+--------------+
| restid | chargeid | chargetime | chargeamount |
+--------+----------+---------------+--------------+
| 1 | 1 | 1536363636363 | 700 |
| 2 | 1 | 1536363636363 | 500 |
| 1 | 1 | 1568789654123 | 500 |
+--------+----------+---------------+--------------+
select * from billingchargedetails;
+----------+--------------------+------------------+
| chargeid | chargename | chargecostperday |
+----------+--------------------+------------------+
| 1 | Base Charge | 50 |
| 2 | Spotlight Listing | 50 |
| 3 | Gold Notification | 500 |
| 4 | Discount (FIRST50) | 18 |
+----------+--------------------+------------------+
A simple join on chargeid ended up not giving me the qty and sum as expected.so i need some form of a left or right outer join, that much i know and tried
I tried a left join as follows:
select restid, B.chargeid, chargename, count(B.chargeid) as qty,
sum(ifnull(chargeamount,0)) as total
from billingcharges as B
left join billingchargedetails as C on B.chargeid=C.chargeid
group by restid,B.chargeid;
+--------+----------+-------------+-----+-------+
| restid | chargeid | chargename | qty | total |
+--------+----------+-------------+-----+-------+
| 1 | 1 | Base Charge | 2 | 1200 |
| 2 | 1 | Base Charge | 1 | 500 |
+--------+----------+-------------+-----+-------+
This does work and sums things but there are missing charges for each restaurant. even if they arent present inside the billinghcarges ie the left table, i need it with qty 0 and total 0.
I tried a right join and a random value was selected by mysql from the non existing entries inside the left table as follows:
select restid, B.chargeid, chargename, count(B.chargeid) as qty,
sum(ifnull(chargeamount,0)) as total
from billingcharges as B
right join billingchargedetails as C on B.chargeid=C.chargeid
group by restid,B.chargeid;
+--------+----------+-------------------+-----+-------+
| restid | chargeid | chargename | qty | total |
+--------+----------+-------------------+-----+-------+
| NULL | NULL | Spotlight Listing | 0 | 0 |
| 1 | 1 | Base Charge | 2 | 1200 |
| 2 | 1 | Base Charge | 1 | 500 |
+--------+----------+-------------------+-----+-------+
The expected output is something like:
restid chargeid chargename qty totalamount
1 1 Base Charge 2 1200
1 2 Spotlight 0 0
1 3 Gold 0 0
1 4 Discount 0 0
2 1 Base Charge 1 500
2 2 Spotlight 0 0
2 3 Gold 0 0
2 4 Discount 0 0
'same as above expected for each restid in billingcharges'
Before you can do the outer join, you need to generate the cross-product of restaurants to charge types.
Something like the following (but I have not tested it):
SELECT R.restid, D.chargename, COUNT(B.chargeid) AS qty,
SUM(IFNULL(B.chargeamount, 0)) AS total
FROM (SELECT DISTINCT restid FROM billingcharges) AS R
CROSS JOIN billingchargedetails AS D
LEFT JOIN billingcharges AS B ON R.restid=B.restid AND D.chargeid=B.chargeid
GROUP BY R.restid, D.chargename;
In this example, the cross-product of R and D is every restaurant crossed with every charge type.
Of course not all of those charges exist for every restaurant. So the outer join to billingcharges finds those rows that do exist for each respective combination of restaurant & charge type.
I'm writing a query in MySQL and it has challenged me. Here is the situation;
Let's assume I have a table named 'status' which keeps data for a TV show like that;
+---------+---------+---------+---------+
| id | season | episode | channel |
+---------+---------+---------+---------+
| 1 | 2 | 10 | a |
| 1 | 3 | 2 | b |
| 1 | 2 | 9 | c |
| 1 | 3 | 1 | d |
| 1 | 3 | 2 | e |
+---------+---------+---------+---------+
I want to retrieve the rows which contains the last released episode of the last season. According to the table above, I expect a result like that
+---------+---------+---------+
| season | episode | channel |
+---------+---------+---------+
| 3 | 2 | b |
| 3 | 2 | e |
+---------+---------+---------+
The max value of the season column is 3. In this case, I have retrieved the rows that have the max value of the episode column where season is equal to 3. I have written a query and it gives the expected result, but I don't think that it is an appropriate query. How could I improve the query below? If needed, I can add extra information or give further examples.
SELECT `season`,
`episode`,
`channel`
FROM `status`
WHERE `tvseriesid` = 1
AND `season` = (SELECT Max(season)
FROM `status`
WHERE `tvseriesid` = 1)
AND `episode` = (SELECT Max(episode)
FROM `status`
WHERE `tvseriesid` = 1
AND `season` = (SELECT Max(season)
FROM `status`
WHERE `tvseriesid` = 1))
Here is a way that puts all the information in one row. However, it is a bit simpler:
select season, episode, group_concat(channel)
from status
where tvseriesid = 1
group by season, episode
order by season desc, episode desc
limit 1;
Following on from this question SELECT all the newest record distinct keyword with a non null value in one column
I now have a problem where I have this data
PRODUCT:
id| product | amount| ownershipid
1 | ipod | 200 | 2
2 | ipod | 250 | 3
3 | ipod | 150 | 4
4 | apple | 100 | 1
5 | apple | 98 | 2
6 | apple | 500 | 3
7 | itunes | NULL | 1
8 | itunes | 50 | 2
9 | itunes | NULL | 3
10 | itunes | NULL | 4
OWNERSHIP:
ownershipid| start | end
1 | 2011-01-01 | 2011-12-31
2 | 2012-01-01 | 2012-12-31
3 | 2014-01-01 | 2014-12-31
4 | 2013-01-01 | 2013-12-31
I need the most recent amount available for each product. I can not do an order by on ownershipId as the most recent data is from 2014. not from 2013. OwnershipId is Autoincrement and we accept historic data.
So, my result should return rows 2, 6 and 8.
Assuming most recent is defined by end, you can do a somewhat convoluted join to get the result;
SELECT p.product, p.amount
FROM product p JOIN ownership o ON p.ownershipid = o.ownershipid
JOIN (
SELECT p.product, MAX(o.end) end
FROM product p JOIN ownership o ON p.ownershipid = o.ownershipid
WHERE p.amount IS NOT NULL GROUP BY p.product) z
ON p.product = z.product AND o.end = z.end;
An SQLfiddle to test with.
The inner query gets the max date that has a non null amount per item.
The outer query gets the amount for that time/product.