MySQL query to get data between and not between where clause - mysql

This MySQL query is to get data from two tables exam_dates and section_strength and join them to get total persons from which sections has completed there exam in march quarter:
select s.section, count(section), r.strength
from exam_dates s
left join section_strength r
on s.section=r.section_name
where s.semester_exam between '2017-01-01' and '2017-03-31'
group by s.section
But this query is showing only those sections name who have completed the exam in march quarter. I want all the name of sections in left side and number of persons completed next column and then the strength of that section.
first table contains=> details of student completed exam on "so and so dates"
example:
id| personal_no| section_name| semester_dates
1 | 777878 | hrm |2017-01-12
2 | 748587 |it |2017-05-10
another table having strength of individual sections:
id|section_name |strength
1 | hrm | 10
2 | it | 15
Now I want my query to show result of all sections name in left side and then total student completed test in march quarter and then total strength of that section.
for eg.
id|section_name|total_completed|strength
1 | hrm | 2 | 10
2 | it | 5 | 15

Your second date is before your first date. Try reversing the order of the dates:
select s.section, count(section), r.strength
from exam_dates s
left join section_strength r on s.section=r.section_name
where s.semester_exam between '2017-03-31' and '2017-01-01'
group by s.section

Related

Need validation that interpretation for a Grouping Query is correct

I am running the following query and at first it appears to give the sub totals for customers and shows by date each customers payment amounts only if that total for all payments is greater than $90,000.
SELECT
Customername,
Date(paymentDate),
CONCAT('$', Round(SUM(amount),2)) AS 'High $ Paying Customers'
FROM Payments
JOIN Customers
On payments.customernumber = customers.customernumber
Group by customername, Date(paymentDate) WITH ROLLUP
having sum(amount)> 90000;
But upon looking at the records for Dragon Souveniers, Ltd. and Euro+ Shopping Channel is is actually showing the paydates that have amounts individually over $90000 as well as the subtotal for that customer as a rollup. For all other customers, their individual payment dates are not reported in the result set and only their sum is if it over $90000. For example Annna's Decorations as 4 payment records and none of them are over 90000 but her sum is reported as the value for the total payments in the query with the rollup. Is this the correct interpretation?
The HAVING clause work correct, It filters all records with a total no above 90000. It also does do this for totals.
When using GROUP BY .... WITH ROLLUP, you can detect the created ROLL UP lines by using the GROUPING() function.
You should add a condition in a way that the desired columns are not filtered.
Simple example:
select a, sum(a), grouping(a<3)
from (select 1 as a
union
select 2
union select 3) x
group by a<3 with rollup;
output:
+---+--------+---------------+
| a | sum(a) | grouping(a<3) |
+---+--------+---------------+
| 3 | 3 | 0 |
| 1 | 3 | 0 |
| 1 | 6 | 1 |
+---+--------+---------------+
this shows that the last line (with grouping(i<3) == 1) is a line containing totals for a<3.

Combine results from 3 sql queries to calculate running stock

I am trying to calculate the stock by product a warehouse had over time. I have the information about today's stock, and also the amount of products sold and purchased by day. So, the calculation for yesterday values would be:
Yesterday_stock=Stock-yesterday_sold_quantity+yesterday_purchased_quantity. My problem is that i should save somewhere the amount of everyday's stock in order to calculate the stock of the previous day. I found that in order to do that i could use over sql clause with order by. But unfortunately, i have sql server 2008 and this is not a choice.
The tables are:
Prdamount which holds the current stock per product (StuPrdID ) and if it is blocked for some reason.
|-------------- |------------------|---------------
| StuPrdID | StuQAmount |prdBlockingReason
|---------------|------------------|-------------
| 12345| 16 |
|---------------|------------------|--------------
| 08889| 12 | expired
|---------------|------------------|------------
Table Moves which holds information about inserts and outputs of products. If MoveCase field has value equal 1 it is an output move, if it is a 2 it is a purchased quantity. Moves table dummy data:
|-------------- |--------------------- -|--------|-------
|MoveItemCode | MoveDate |MoveCase|MoveRealQty
|---------------|---------------------- |--------|-------
| 12345 |2018-06-24 00:00:00.000| 1 |14
|---------------|-----------------------|--------|--------
| 08889 |2018-06-24 00:00:00.000| 2 |578
|---------------|-----------------------|--------|--------
and table Product with information related with data:
|-------------- |------------------|
| PrdCode | PrdDespription |
|---------------|------------------|
| 12345| Orange juice|
|---------------|------------------|
| 08889| Chocolate|
|---------------|------------------|
I want an output like this:
|------------|--------------------- -|--------|--------------|------------
|Prdcode | PrdDescription |Stock |Stock 18/07/03|Stock 18/7/02
|------------|---------------------- |--------|--------------|------------
| 12345 |Orange Juice | 80 |50 34
|----------- |-----------------------|--------|--------------|------------
| 08889 |Chocolate | 45 |82 17
|------------|-----------------------|--------|--------------|-------------
this query gives me the running stock:
select
product.PrdCode,
product.PrdDescr,
SUM(StuQAmount) as Stock
from prdamount
left join product on (product.PrdID=prdamount.StuPrdID)
where prdamount.prdBlockingReason=' '
group by product.PrdCode,product.PrdDescr
order by product.PrdCode asc
This query gives me the quantity sold by product per day:
select
moves.MoveItemCode,
prd.PrdDescr,
moves.MoveDate,
SUM(MoveRealQty) as 'sold_quantity'
from moves
left join prd on (moves.MoveItemCode=product.PrdCode)
where (moves.MoveDate>'2018-06-01' and and moves.MoveCase=1)
group by moves.MoveItemCode,product.PrdDescr,moves.MoveDate
order by moves.MoveItemCode asc,moves.MoveDate asc
And this query gives me the quantity purchases by product per day:
select
moves.MoveItemCode,
prd.PrdDescr,
moves.MoveDate,
SUM(MoveRealQty) as 'Purchased_Quantity'
from Moves
left join product on (moves.MoveItemCode=product.PrdCode)
where (moves.MoveDate>'2018-06-01' and moves.MoveCase=2)
group by moves.MoveItemCode,product.PrdDescr,moves.MoveDate
order by moves.MoveItemCode asc,moves.MoveDate asc
I tried to combine these 3 queries into one using subqueries, but it didn't work. So how can i accomplish the result that i want? Sorry if the question is silly, i am a beginner in sql
try this,
select
product.PrdCode,
moves.MoveItemCode,
product.PrdDescr,
moves.MoveDate,
SUM( case when moves.MoveCase=1 then MoveRealQty else 0 end) as 'sold_quantity',
SUM( case when moves.MoveCase=2 then MoveRealQty else 0 end) as 'Purchased_Quantity',
(select SUM(StuQAmount) from prdamount where StuPrdID = product.PrdID and prdBlockingReason=' ')
from moves
left join product on (moves.MoveItemCode=product.PrdCode)
where (moves.MoveDate>'2018-06-01')
group by moves.MoveItemCode,product.PrdDescr,moves.MoveDate, product.PrdCode
order by moves.MoveItemCode asc,moves.MoveDate asc

Self Join MYSQL Parent Child

For some reason this is eluding me tonight. I have 3 tables, appointments, clients, tasks. I am trying to get all the appointments for today or tomorrow, check the users table to pull the current clients, and any family members, and then pull tasks that meet another criteria to get a full list of tasks for the day or past due.
On the client table we are importing information from another datasource maintaining the original id as reference_id, if they don't have a parent_id, they are the parent, otherwise they are children.
appointment table
id | user_id | client_id | start_at
1 1 2 2018-02-15
2 1 1 2018-02-15
3 1 2 2018-02-15
4 2 4 2018-02-15
clients table:
id | reference_id | parent_id | user_id
1 35 null 1
2 36 35 1
3 37 35 1
4 35 null 2
5 36 35 2
tasks table
id | client_id | task | due_date
1 2 do something 2018-02-15
2 4 do something 2018-01-10
3 2 do something 2018-02-01
4 2 do something 2018-05-15
I got started trying to join the table onto itself, but when I try combining the parent it ends up killing all results, but only when I add WHERE parent_id > 0 to the query. Before that I am getting about 40 results, but should be well over 100. In the dataset, I have 50 appointments, some of the users have 2-5 children / relationship but I am not sure why since I am doing LEFT JOIN instead of inner join, if anything I should start ending up with redundant extra results.
SELECT
start_at,
clients.id,
clients.reference_id,
clients.parent_id,
clients.first_name,
clients.last_name,
children.user_id,
children.first_name,
children.last_name,
children.reference_id,
children.parent_id,
parents.last_name
FROM
`reminderdental2`.`appointments` AS appointment
INNER JOIN clients AS clients
ON appointment.patient_id = clients.id
INNER JOIN clients AS children
ON clients.parent_id = children.parent_id
LEFT JOIN
(SELECT
reference_id,
user_id,
last_name,
first_name,
parent_id
FROM
clients WHERE parent_id > 0) AS parents
ON clients.parent_id = parents.reference_id
WHERE clients.user_id = '27'
AND children.user_id = '27'
AND parents.user_id = '27'
AND start_at > NOW() - INTERVAL 1 DAY
AND start_at < NOW() + INTERVAL 1 DAY
Is there a better way to design this than joining the client table 3 times? Why did it kill the query adding the WHERE parent_id > 0?

Listing rows not only when criteria are met

I have three tables:
1 dates - contains column date
2 book - contains columns room, date and surname
3 people - contains column surname
I am able to get dates where there were people in rooms on certain days within the range of dates.
SELECT date, IFNULL(surname, 'ghost')
FROM book JOIN dates ON book.date=dates.date JOIN people ON people.surname=book.surname
WHERE room = 113
AND date BETWEEN '2015-01-01' AND '2015-01-07'
+------------+-----------+
| Date | Surname |
+------------+-----------+
| 2015-01-02 | Surname 1 |
| 2015-01-05 | Surname 2 |
+------------+-----------+
How do I return a full list of dates, including those where there was nobody in a room so every date from given range is printed and if no people in the specified room, then 'ghost' is printed instead?
You need to use a LEFT JOIN
SELECT dates.date, IFNULL(book.surname, 'ghost')
FROM dates
LEFT JOIN book
ON book.date=dates.date
AND book.room = 113
-- LEFT JOIN people ON people.surname=book.surname
WHERE dates.date BETWEEN '2015-01-01' AND '2015-01-07'
Note that book.room = 113 needs to be in the ON clause. Using it in the WHERE clause would convert the LEFT JOIN to INNER JOIN.

select particular items ordered n times

i have two tables, one invoice and the other the details where i need to select products ordered n times by a particular customer within a date range
the tables in part looks like this
Invoice
invid | custid | invdate
----------------------------
101 | 11 | 2014-2-10
102 | 22 | 2014-2-15
103 | 22 | 2014-3-01
104 | 11 | 2014-3-14
Details
invid | item
------------
101 | bread
102 | bread
103 | chips
104 | chips
102 | bread
103 | bread
104 | chips
101 | bread
from the code above, i need to select say all customers who ordered the same items 2 times or more within 2014-2-10 and 2014-3-09, excluding any customer who purchased the same item in the week 2014-3-10 to 2014-3-14
for example
if customer orders bread 2 times between date1 and date2 and did not order the same bread between date3 and date4 then it should be in the output
and date the expected output should be
custid | item | item_count
22 | bread | 2
the custid 11 would have NOT fit the list, because they also purchased in the week 2014-3-10 to 2014-3-14, but it they did not purchased the same item in the passed dates
this is what i tried
SELECT
i.custid, d.ITEM,COUNT(d.ITEM) as orders
From `details` d
LEFT JOIN `invoices` i on i.invid= d.invid
WHERE
i.invdate >= '2014-2-10' AND
i.invdate <= '2014-3-14' AND
i.custid NOT IN
(SELECT custid FROM `invoices` WHERE invdate >= '2014-3-10')
Group By i.invid, d.ITEM
HAVING COUNT(d.ITEM) >= 2
when i run again the full table, i get 1 item instead of 6. I did manually using excel through a number of functions to be sure, in this case none
Typical MySQL error. You mistakenly group by invid instead of custid.
SELECT
i.custid, d.ITEM, COUNT(d.ITEM) as orders
From `details` d
LEFT JOIN `invoices` i on i.invid= d.invid
WHERE
i.invdate >= '2014-2-10' AND
i.invdate <= '2014-3-14' AND
i.custid NOT IN
(SELECT custid FROM `invoices` WHERE invdate >= '2014-3-10')
Group By i.custid, d.ITEM
HAVING COUNT(d.ITEM) >= 2;
EDIT: Okay, here is a closer look at it.
Correct the GROUP BY as already mentioned.
You outer join invoices although there should be no details record without an invoices record. Change this to INNER JOIN.
You are confusing dates. The purchase date shall be between '2014-2-10' and '2014-3-09' and must not be between '2014-3-10' to '2014-3-14'
Then: You don't want to exclude customers who bought something in that latter week. You want to exclude customer-item combinations that occured then.
My suggestion: select from both date ranges and check then if all macthes for a customer-item combination are within the desired week and still have a count of at least two:
select
i.custid,
d.item,
count(d.item) as orders
from invoices i
inner join details d on d.invid = i.invid
where i.invdate between '2014-2-10' and '2014-3-09'
or i.invdate between '2014-3-10' and '2014-3-14'
group by i.custid, d.item
having count(*) >= 2 and max(i.invdate) between '2014-2-10' and '2014-3-09;
SELECT i1.custid, d1.ITEM, COUNT(*) orders
FROM (invoices i1 JOIN details d1 USING (invid))
LEFT JOIN (invoices i2 JOIN details d2 USING (invid))
ON i2.custid = i1.custid
AND d2.ITEM = d1.ITEM
AND i2.invdate BETWEEN '2014-03-10' AND '2014-03-14'
WHERE i1.invdate BETWEEN '2014-02-10' AND '2014-03-09'
AND i2.custid IS NULL
GROUP BY i1.custid, d1.ITEM
HAVING orders >= 2
See it on sqlfiddle.