MySQL Joining multiple select satement containing multiple values for View - mysql

I have a Table having all IN detail
+----------+------------+-----------+
| staff_id | date | time |
+----------+------------+-----------+
| 1 | 2015-02-20 | 07:00 |
| 2 | 2015-02-20 | 07:01 |
| 3 | 2015-02-20 | 07:05 |
| 1 | 2015-02-20 | 07:02 |
| 1 | 2015-02-20 | 07:04 |
+----------+--------------+---------+
another Table having all OUT detail
+----------+------------+-----------+
| staff_id | date | time |
+----------+------------+-----------+
| 1 | 2015-02-20 | 13:00 |
| 2 | 2015-02-20 | 13:45 |
| 3 | 2015-02-20 | 13:45 |
| 1 | 2015-02-20 | 13:47 |
| 1 | 2015-02-20 | 13:48 |
+----------+--------------+---------+
What required result is
Time In, min val and Time Out, max value
+----------+------------+-----------+
| staff_id | date | time IN | Time Out
+----------+------------+-----------+
| 1 | 2015-02-20 | 07:00 | 13:48
| 2 | 2015-02-20 | 07:01 | 13:45
What Im doing is
SELECT *
FROM
(SELECT sai.staff_id AS staff_id_in,
sai.date AS date_in,
sai.time AS time_in,
sai.ip4 AS ip4_in,
sai.location_id AS location_id_in,
'1' AS atd_in
FROM staff_attendance_in sai
ORDER BY staff_id ASC, time ASC) AS sub
GROUP BY staff_id_in,
date_in
UNION
SELECT *
FROM
(SELECT sao.staff_id AS staff_id_out,
sao.date AS date_out,
sao.time AS time_out,
sao.ip4 AS ip4_out,
sao.location_id AS location_id_out,
'2' AS atd_out
FROM staff_attendance_out sao
ORDER BY time DESC) AS sub
GROUP BY staff_id_out,
date_out
but I am not able to generate view from the query... neither join

Try this:-
SELECT I.staff_id, I.date, MIN(I.time_IN), MAX(O.Time Out)
FROM IN I JOIN OUT O
ON I.staff_id = O.staff_id
GROUP BY I.staff_id, I.date;
I think this can help you.

Related

MySQL Merge two queries based on mutual column

I have two queries that retrieve records from 2 different tables that are almost alike and I need to merge them together.
Both have created_date which is of type datetime and I'm casting this column to date because I want to group and order them by date only, I don't need the time.
First query:
select cast(created_date as date) the_date, count(*)
from question
where user_id = 2
group by the_date
order by the_date;
+------------+----------+
| the_date | count(*) |
+------------+----------+
| 2021-01-02 | 1 |
| 2021-02-10 | 1 |
| 2021-02-14 | 5 | -- this line contains a mutual date
| 2021-03-16 | 1 |
| 2021-03-26 | 3 |
| 2021-03-27 | 23 |
| 2021-03-28 | 5 |
| 2021-03-29 | 1 |
+------------+----------+
Second query:
select cast(created_date as date) the_date, count(*)
from answer
where user_id = 2
group by the_date
order by the_date;
+------------+----------+
| the_date | count(*) |
+------------+----------+
| 2021-02-08 | 2 |
| 2021-02-14 | 1 | -- this line contains a mutual date
| 2021-04-05 | 5 |
| 2021-04-06 | 2 |
+------------+----------+
What I need is to merge them like this:
+------------+---------------+---------------+
| the_date | count(query1) | count(query2) |
+------------+---------------+---------------+
| 2021-01-02 | 1 | 0 | -- count(query2) is 0 bc. it's not in the second query
| 2021-02-08 | 0 | 2 | -- count(query1) is 0 bc. it's not in the first query
| 2021-02-10 | 1 | 0 |
| 2021-02-14 | 5 | 1 | -- mutual date
| 2021-03-16 | 1 | 0 |
| 2021-03-26 | 3 | 0 |
| 2021-03-27 | 23 | 0 |
| 2021-03-28 | 5 | 0 |
| 2021-03-29 | 1 | 0 |
| 2021-04-05 | 0 | 5 |
| 2021-04-06 | 0 | 2 |
+------------+---------------+---------------+
Basically what I need is to have all dates together and for each date to have the corresponding values from those two queries.
try something like this.
SELECT the_date , max(cnt1) , max(cnt2)
FROM (
select cast(created_date as date) the_date, count(*) AS cnt1 , 0 as cnt2
from question
where user_id = 2
group by the_date
order by the_date
UNION ALL
select cast(created_date as date) the_date, 0, count(*)
from answer
where user_id = 2
group by the_date
order by the_date
) as t1
GROUP BY the_date
ORDeR BY the_date;

Retrieving data from the row containing the closest date to today with whereDate

I want to sort by price after filtering and grouping by date. However, because there are more than one relation, I cannot get the result I want.
The result I want is to get the price of the relation that is the closest to the end_date and sort it accordingly.
For this, the query, sql output, tables and demo page are as follows.
Thanks in advance ..
demo sqlfiddle
$query->join('tableB', 'tableA.id', '=', 'tableB.pro_id')
->select('tableA.*', 'tableB.start_date', 'tableB.end_date', 'tableB.old_daily')
->where(function($sq) {
$today = Carbon::now()->format('Y-m-d');
$sq->whereDate('end_date', '>=', $today);
})
->groupBy('tableA.id')
->orderBy('price', desc);
Query:
select `tableA`.*, `tableB`.`start_date`, `tableB`.`end_date`, `tableB`.`price`
from `tableA`
inner join `tableB` on `tableA`.`id` = `tableB`.`pro_id`
where (date(`end_date`) >= 2021-03-07)
group by `tableA`.`id`
order by `price` desc
tableA
| id | title |
|----|-------|
| 1 | pro1 |
| 2 | pro2 |
| 3 | pro3 |
tableB
| id | start_date | end_date | price | pro_id |
|----|------------|------------|-------|--------|
| 1 | 2021-06-01 | 2021-06-05 | 750 | 2 |
| 2 | 2021-05-01 | 2021-05-05 | 850 | 2 |
| 3 | 2021-04-01 | 2021-04-05 | 650 | 2 |
| 4 | 2021-06-01 | 2021-06-05 | 2750 | 1 |
| 5 | 2021-05-01 | 2021-05-05 | 2850 | 1 |
| 6 | 2021-04-01 | 2021-04-05 | 2650 | 1 |
| 7 | 2021-06-01 | 2021-06-05 | 1750 | 3 |
| 8 | 2021-05-01 | 2021-05-05 | 1850 | 3 |
| 9 | 2021-04-01 | 2021-04-05 | 1650 | 3 |
this query gives the result you want.
It would be a good choice to use "right join" in this step.
sqlfiddle
select `tableA`.*, `tableB`.`start_date`, `tableB`.`end_date`, `tableB`.`price`
from `tableA`
right join(
SELECT id, start_date, end_date, pro_id, price, DATEDIFF(`tableB`.`end_date`, '2021-03-07') diff
FROM `tableB`
GROUP BY id order by diff asc
) `tableB` on `tableA`.`id` = `tableB`.`pro_id`
where (date(`end_date`) >= '2021-03-07')
group by `tableA`.`id`
order by `price` desc
the closest to the end_date and sort it accordingly.
you should find the difference between the given date and end date then sort ascendingly.
ORDER BY DATEDIFF(end_date, '2021-03-07') ASC

SQL query to get Net Salse by every month

I'm looking for a query to get monthly net sales I tried this far but I couldn't get what I want.
this is my Order Table
+----------+-----------+--------+------------+---------------+-------------+-----------+---------+---------+
| orderID | custID | userID | orderDate | paymentMethod | grossAmount | netAmount | cash | balance |
+----------+-----------+--------+------------+---------------+-------------+-----------+---------+---------+
| INV-0001 | CUST-0001 | U-001 | 2020-05-01 | Cash Pay | 525.00 | 525.00 | 550.00 | 25.00 |
| INV-0002 | CUST-0001 | U-001 | 2020-05-01 | Cash Pay | 240.00 | 240.00 | 250.00 | 10.00 |
| INV-0003 | CUST-0001 | U-001 | 2020-05-01 | Cash Pay | 220.00 | 220.00 | 250.00 | 30.00 |
| INV-0004 | CUST-0001 | U-001 | 2020-04-30 | Cash Pay | 895.00 | 895.00 | 1000.00 | 105.00 |
| INV-0005 | CUST-0001 | U-001 | 2020-04-30 | Cash Pay | 300.00 | 300.00 | 500.00 | 200.00 |
| INV-0006 | CUST-0001 | U-001 | 2020-04-30 | Cash Pay | 230.00 | 230.00 | 250.00 | 20.00 |
+----------+-----------+--------+------------+---------------+-------------+-----------+---------+---------+
This is my CustomerReturn Table
+-------+----------+------------+--------+------------+-----------+-----------+-------------+
| retID | orderID | itemCode | userID | retDate | returnQty | unitPrice | totalAmount |
+-------+----------+------------+--------+------------+-----------+-----------+-------------+
| 1 | INV-0001 | 1800232050 | U-001 | 2020-05-01 | 1.00 | 100.00 | 100.00 |
| 2 | INV-0002 | 1909873674 | U-001 | 2020-05-01 | 2.00 | 55.00 | 110.00 |
| 3 | INV-0004 | 1800232050 | U-001 | 2020-04-30 | 1.00 | 100.00 | 100.00 |
+-------+----------+------------+--------+------------+-----------+-----------+-------------+
the formula is (total of the monthly bill(Order.netAmount) - a total of monthly return (CustomerReturn.totalAmount))
in need to get net sales every year of every month.
select orderDate,sum(netAmount)-sum(totalAmount) from `Order` o,CustomerReturn r where o.orderID=r.orderID GROUP BY orderDate;
when I run this query it shows me this
+------------+---------------------------------+
| orderDate | sum(netAmount)-sum(totalAmount) |
+------------+---------------------------------+
| 2020-04-30 | 795.00 |
| 2020-05-01 | 555.00 |
+------------+---------------------------------+
but it should be Like this
+------------+---------------------------------+
| orderDate | sum(netAmount)-sum(totalAmount) |
+------------+---------------------------------+
| 2020-04-30 | 1425.00 |
| 2020-05-01 | 775.00 |
+------------+---------------------------------+
please help me. Thank you.!
Your query is good, it is fetching all records when there is a match on OrderId in the table CustomerReturn and doing the sums as you requested, however there are no returns for the order INV-0003, so this condition o.orderID=r.orderID is not valid when it comes to that record and it is ignoring that data. Doing a left join will fix the issue.
select
o.orderDate,
sum(o.netAmount)-sum(case when cr.totalAmount is null then 0 else cr.totalAmount end)
from
Orders o
left join
CustomerReturn cr
on
o.orderID = cr.orderID
group by
o.orderDate
A left join will cause cr.totalAmount to have null values in case there is no match for o.orderID=r.orderID then we use this part; case when cr.totalAmount is null then 0 else cr.totalAmount end to fix that null issue.
Because you are joining on dates that is why you are not getting correct answer, as order date and return date can have different month.
Better if you extract the month and then do sum as shown in below query, and here is the demo.
select
o.mm as month,
sum(total_net_amount - total_amount) as total
from
(
select
month(orderDate) as mm,
sum(netAmount) as total_net_amount
from Orders
group by
month(orderDate)
) o
join
(
select
month(retDate) as mm,
sum(totalAmount) as total_amount
from CustomerReturn
group by
month(retDate)
) cr
on o.mm = cr.mm
group by
o.mm
Output:
*--------------*
|month | total |
*--------------*
| 5 | 775 |
| 4 | 1325 |
*--------------*
Learn to use proper, explicit, standard, readable JOIN syntax. As pointed out in another answer, you want a LEFT JOIN. That said, the simpler way to write the logic is:
select o.orderDate,
sum(o.netAmount)- coalesce(sum(cr.totalAmount, 0)) as net_amount
from Orders o left join
CustomerReturn cr
on o.orderID = cr.orderID
group by o.orderDate;

MySql query SUM from two tables group by month

I have three tables: tbl_job1 , tbl_job2 and tbl_users.
tbl_job1:
ID| DataComplited | Profit | UserID |
===================================
1 | 2017-01-01 | 100 | 1 |
2 | 2017-02-01 | 200 | 1 |
3 | 2017-03-01 | 150 | 1 |
4 | 2017-01-01 | 400 | 2 |
5 | 2017-01-01 | 120 | 1 |
6 | 2017-02-03 | 30 | 1 |
tbl_job2:
ID| DataComplited | Profit | UserID |
===================================
1 | 2017-02-01 | 50 | 1 |
2 | 2017-03-01 | 20 | 1 |
3 | 2017-02-03 | 20 | 1 |
4 | 2017-02-03 | 50 | 1 |
tbl_users:
ID| fullname |
==============
1 | Robert |
2 | Maria |
I want to see:
Fullname | Year | Month | Profit 1 | Profit 2 | Total |
==========================================================
Maria | 2017 |January | 400.00 | |400.00 |
Robert | 2017 |January | 220.00 | |220.00 |
| |February| 230.00 | 120.00 |350.00 |
| | March | 150.00 | 20.00 |170.00 |
But I get:
Fullname | Year | Month | Profit 1 | Profit 2 | Total |
==========================================================
Maria |2017 |January | 400.00 | |400.00 |
Robert |2017 |January | 220.00 | |220.00 |
| |February| 260.00 | 120.00 |380.00 |
| | March | 150.00 | 20.00 |170.00 |
Please see what Robert's got in February.
Sorry about my English, I'm Russian. But I think you can see everything on those tables. Actually I want to see sum from two jobs for every month.
I'm new on MySql, I tried this code:
SELECT
year(tbl_job1.DataComplited) AS `Year`,
DATE_FORMAT(tbl_job1.DataComplited, '%M') AS `Month`,
DATE_FORMAT(tbl_job1.DataComplited, '%m') AS Month_ord,
tbl_users.fullname,
SUM(tbl_job1.Profit) AS Profit_1
SUM(tbl_job2.Profit) AS Profit_2 ,
(SUM(tbl_job1.profit)) + (SUM(COALESCE(tbl_job2.profit, 0))) AS Total
FROM tbl_job1
LEFT OUTER JOIN tbl_job2 ON tbl_job1.DataComplited = tbl_job2.DataComplited
INNER JOIN tbl_users ON tbl_job1.UserID = tbl_users.ID
GROUP BY tbl_users.fullname,
month(tbl_job1.DataComplited),
DATE_FORMAT(`month`, '%m'),year
ORDER BY tbl_users.fullname,
year(tbl_job1.DataComplited),
DATE_FORMAT(tbl_job1.DataComplited, '%M')
Please help me.
thank you, I but I decided by myself.
SELECT
year(a.DataComplited) AS `Year`,
DATE_FORMAT(a.DataComplited, '%M') AS `Month`,
tbl_users.fullname,
SUM(a.Profit) AS Profit_1,
b.Profit AS Profit_2,
SUM(COALESCE(a.Profit, 0)) + COALESCE(b.Profit, 0) as Total
FROM tbl_job1 as a
INNER JOIN tbl_users ON a.UserID = tbl_users.ID
LEFT OUTER JOIN
(
SELECT
DATE_FORMAT(DataComplited, '%M') AS `Month`,
DataComplited,
SUM(COALESCE(tbl_job2.profit, 0)) AS Profit
FROM tbl_job2
GROUP BY month(DataComplited), DATE_FORMAT(`month`, '%m')
) AS b USING (DataComplited)
GROUP BY tbl_users.fullname, month(a.DataComplited), DATE_FORMAT(`month`, '%m'), year
ORDER BY tbl_users.fullname, year(a.DataComplited), DATE_FORMAT(a.DataComplited, '%m')

help in forming mysql query to find free(available) venues/resources for a give date range

I have tables & data like this:
venues table contains : id
+----+---------+
| id | name |
+----+---------+
| 1 | venue 1 |
| 2 | venue 2 |
---------------
event_dates : id, event_id, event_from_datetime, event_to_datetime, venue_id
+----+----------+---------------------+---------------------+----------+
| id | event_id | event_from_datetime | event_to_datetime | venue_id |
+----+----------+---------------------+---------------------+----------+
| 1 | 1 | 2009-12-05 00:00:00 | 2009-12-07 00:00:00 | 1 |
| 2 | 1 | 2009-12-09 00:00:00 | 2009-12-12 00:00:00 | 1 |
| 3 | 1 | 2009-12-15 00:00:00 | 2009-12-20 00:00:00 | 2 |
+----+----------+---------------------+---------------------+----------+
This is my requirement: I want venues that will be free on 2009-12-06 00:00:00
i.e.
I should get
|venue_id|
|2 |
Currently I'm having the following query,
select ven.id , evtdt.event_from_datetime, evtdt.event_to_datetime
from venues ven
left join event_dates evtdt
on (ven.id=evtdt.venue_id)
where evtdt.venue_id is null
or not ('2009-12-06 00:00:00' between evtdt.event_from_datetime
and evtdt.event_to_datetime);
+----+---------------------+---------------------+
| id | event_from_datetime | event_to_datetime |
+----+---------------------+---------------------+
| 1 | 2009-12-09 00:00:00 | 2009-12-12 00:00:00 |
| 2 | 2009-12-15 00:00:00 | 2009-12-20 00:00:00 |
| 3 | NULL | NULL |
| 5 | NULL | NULL |
+----+---------------------+---------------------+
If you note the results, its not including venue id 1 where date is in between 2009-12-06 00:00:00 but showing other bookings.
Please help me correct this query.
Thanks in advance.
SELECT *
FROM venue v
WHERE NOT EXISTS
(
SELECT NULL
FROM event_dates ed
WHERE ed.venue_id = v.id
AND '2009-12-06 00:00:00' BETWEEN ed.event_from_datetime AND ed.event_to_datetime
)
or not ('2009-12-06 00:00:00' between evtdt.event_from_datetime
and evtdt.event_to_datetime);
12/6/2009 is between 12/5/09 and 12/7/09... that's why venue_id 1 is being excluded... what is it you're trying to extract from the data exactly?
The join query you've constructed says, take the venues table and for each row of it that has a matching venue_id make a copy of the venue table row and append the matching row. So if you just did:
select *
from venues ven
left join event_dates evtdt
on (ven.id=evtdt.venue_id);
It would yield:
+----+---------+------+----------+---------------------+---------------------+----------+
| id | name | id | event_id | event_from_datetime | event_to_datetime | venue_id |
+----+---------+------+----------+---------------------+---------------------+----------+
| 1 | venue 1 | 1 | 1 | 2009-12-05 00:00:00 | 2009-12-07 00:00:00 | 1 |
| 1 | venue 1 | 2 | 1 | 2009-12-09 00:00:00 | 2009-12-12 00:00:00 | 1 |
| 2 | venue 2 | 3 | 1 | 2009-12-15 00:00:00 | 2009-12-20 00:00:00 | 2 |
+----+---------+------+----------+---------------------+---------------------+----------+
If you then added your condition, which states the date of interest is not between the from and to date of the event, the query looks like:
select *
from venues ven
left join event_dates evtdt
on (ven.id=evtdt.venue_id)
where not ('2009-12-06' between evtdt.event_from_datetime and evtdt.event_to_datetime)
Which yields a result of:
+----+---------+------+----------+---------------------+---------------------+----------+
| id | name | id | event_id | event_from_datetime | event_to_datetime | venue_id |
+----+---------+------+----------+---------------------+---------------------+----------+
| 1 | venue 1 | 2 | 1 | 2009-12-09 00:00:00 | 2009-12-12 00:00:00 | 1 |
| 2 | venue 2 | 3 | 1 | 2009-12-15 00:00:00 | 2009-12-20 00:00:00 | 2 |
+----+---------+------+----------+---------------------+---------------------+----------+
These are my actual experimental results with your data in MySQL.
If you want to get the venue_ids that are free on the proposed date then you would write something like:
select ven.id, SUM('2009-12-06' between evtdt.event_from_datetime and evtdt.event_to_datetime) as num_intersects
from venues ven left join event_dates evtdt on (ven.id=evtdt.venue_id)
group by ven.id
having num_intersects = 0;
which yields:
+----+----------------+
| id | num_intersects |
+----+----------------+
| 2 | 0 |
+----+----------------+
this also comes up with the right answer (without modification) in the case where you have a venue with no events in the event_date table.
At a guess, if you remove not from
or not ('2009-12-06 00:00:00' between evtdt.event_from_datetime
and evtdt.event_to_datetime)
this will then return row 1 from event dates but not the other event date rows.
I say "at a guess" because your where clause is a bit hard to understand. Maybe you mean
select ven.id , evtdt.event_from_datetime, evtdt.event_to_datetime
from venues ven
left join event_dates evtdt
on (ven.id=evtdt.venue_id)
where '2009-12-06 00:00:00' between evtdt.event_from_datetime
and evtdt.event_to_datetime;