Combine count(distinct) with complicate select condition mysql - mysql

I have two working mysql select statements which I'd like to combine:
SELECT
t2.*,
t1.Lang,
Filmname,
ColFI
FROM Timetable t2, Contenttable t1
WHERE DATE_ADD(STR_TO_DATE(CONCAT('201825',' Thursday'), '%x%v %W'), INTERVAL 0 DAY) = DateSZ
AND RoomSZ =1 AND t2.idFI = t1.id
AND deleteSZ = false
ORDER BY TimeSZ
giving me (and of course some other irrelevant columns) for a specific day:
+----------+-------+------+------+------------+
| Filmname | time | idFI | Lang | DateSZ |
+----------+-------+------+------+------------+
| firstfi | 12:00 | 22 | eng | 2018-06-29 |
+----------+-------+------+------+------------+
| sencofi | 15:00 | 44 | fra | 2018-06-29 |
second:
SELECT
idFI,
COUNT(DISTINCT (case when Yweek < 201825 then Yweek end)) AS Week
FROM `Timetable`
GROUP BY idFI
giving me
+-------+------+
| Week | idFI |
+-------+------+
| 2 | 22 |
+-------+------+
| 1 | 44 |
My Timetable table is looking somewhat like this (plus some more columns):
+----------+-------+------+--------+------------+
| Filmname | time | idFI | Yweek | DateSZ |
+----------+-------+------+--------+------------+
| firstfi | 12:00 | 22 | 201825 | 2018-06-29 |
+----------+-------+------+--------+------------+
| firstfi | 18:00 | 22 | 201824 | 2018-06-21 |
+----------+-------+------+--------+------------+
| firstfi | 13:00 | 22 | 201823 | 2018-06-12 |
+----------+-------+------+--------+------------+
| sencofi | 15:00 | 44 | 201825 | 2018-06-29 |
+----------+-------+------+--------+------------+
| sencofi | 18:00 | 44 | 201823 | 2018-06-12 |
+----------+-------+------+--------+------------+
| sencofi | 10:00 | 44 | 201823 | 2018-06-13 |
My problem is, that if I insert the count(distinct) into the first select statement, it isn't working because it only counts rows witch meets all the where clauses in statement nr. 1. How can I combine these statements?
Edit:
Answer from #MKhalidJunaid, but not working with my formatting:
SELECT t2.*, t1.Lang, Filmname, ColFI, t3.Week DATE_FORMAT(DateSZ, '%d.%m.%y') AS DateSZ, TIME_FORMAT(TimeSZ, '%H:%i') AS TimeSZ
FROM Timetable t2
JOIN Contenttable t1 ON t2.idFI = t1.id
JOIN (
SELECT idFI, COUNT(DISTINCT (case when Yweek < 201825 then Yweek end)) AS Week
FROM Timetable
GROUP BY idFI
) t3 ON t2.idFI = t3.idFI
WHERE DATE_ADD(STR_TO_DATE(CONCAT('201825',' Thursday'), '%x%v %W'), INTERVAL 0 DAY) = DateSZ
AND RoomSZ =1
AND deleteSZ = false
ORDER BY TimeSZ

You could use a derived sub select for your count query and then join with your first query as
SELECT t2.*, t1.Lang, Filmname, ColFI , t3.Week
FROM Timetable t2
JOIN Contenttable t1 ON t2.idFI = t1.id
JOIN (
SELECT idFI, COUNT(DISTINCT (case when Yweek < 201825 then Yweek end)) AS Week
FROM Timetable
GROUP BY idFI
) t3 ON t2.idFI = t3.idFI
WHERE DATE_ADD(STR_TO_DATE(CONCAT('201825',' Thursday'), '%x%v %W'), INTERVAL 0 DAY) = DateSZ
AND RoomSZ =1
AND deleteSZ = false
ORDER BY TimeSZ
Also don't use old syntax for joining tables use explicit syntax using join keyword

Related

How query which employee has been full-time employeed

I have the following MySQL table:
+----+---------+----------------+------------+
| id | user_id | employment_type| date |
+----+---------+----------------+------------+
| 1 | 9 | full-time | 2013-01-01 |
| 2 | 9 | half-time | 2013-05-10 |
| 3 | 9 | full-time | 2013-12-01 |
| 4 | 248 | intern | 2015-01-01 |
| 5 | 248 | full-time | 2018-10-10 |
| 6 | 58 | half-time | 2020-10-10 |
| 7 | 248 | NULL | 2021-01-01 |
+----+---------+----------------+------------+
I want to query, for example, which employees were full-time employed on 2014-01-01.
Which SQL query I need to pass to get the correct result?
In this case, the result will be an employee with user_id=9;
Is this table properly structured to be possible to get such a result?
If your version of MySql is 8.0+ you can do it with FIRST_VALUE() window function:
SELECT DISTINCT user_id
FROM (
SELECT user_id,
FIRST_VALUE(employment_type) OVER (PARTITION BY user_id ORDER BY date DESC) last_type
FROM tablename
WHERE date <= '2014-01-01'
) t
WHERE last_type = 'full-time'
For previous versions of MySql you can do it with NOT EXISTS:
SELECT t1.user_id
FROM tablename t1
WHERE t1.date <= '2014-01-01' AND t1.employment_type = 'full-time'
AND NOT EXISTS (
SELECT 1
FROM tablename t2
WHERE t2.user_id = t1.user_id AND t2.date BETWEEN t1.date AND '2014-01-01'
AND COALESCE(t2.employment_type, '') <> t1.employment_type
)
See the demo.
Results:
| user_id |
| ------- |
| 9 |
You want the most recent record on or before that date. I would use row_number():
select t.*
from (select t.*,
row_number() over (partition by user_id order by date desc) as seqnum
from t
where date <= '2014-01-01'
) t
where seqnum = 1 and employment_type = 'full_time';
A fun method that just uses group by is:
select t.user_id
from t
where t.date <= '2014-01-01'
group by t.user_id
having max(date) = max(case when employment_type = 'full_time' then date end);
This checks that the maximum date -- before the cutoff -- is the same as the maximum date for 'full-time'.

How to get records for last 3 months while grouping by each month

Please how do I sum records in my MySQL table for the last 3 months but group them by month.
I want something like this:
select SUM(amount) from table where.....
group by month
I am doing the below but it is not returning any results
SELECT MONTHNAME(a.created_at) MONTH, YEAR(a.created_at) YEAR, SUM(a.credit) as credit, SUM(a.debit)
FROM telco_transactions AS a
WHERE a.telco_id = '1' and DATE(a.created_at) = DATE_ADD(NOW(), INTERVAL -3 MONTH)
GROUP BY MONTHNAME(a.created_at), YEAR(a.created_at);
select T.date_time, SUM(T.amount) from (
-> select * from TEST_TABLE where date_time >= DATE_ADD(CURDATE(), INTERVAL -3 MONTH) and date_time <= CURDATE())
-> as T GROUP BY MONTH(T.date_time);
The table test_table looks like
+------------+--------+
| date_time | amount |
+------------+--------+
| 2017-12-24 | 30 |
| 2017-09-24 | 30 |
| 2017-12-04 | 30 |
| 2017-11-24 | 30 |
| 2017-11-09 | 30 |
| 2017-10-24 | 30 |
+------------+--------+
and the output of the query looks like
+------------+---------------+
| date_time | SUM(T.amount) |
+------------+---------------+
| 2017-09-24 | 30 |
| 2017-10-24 | 30 |
| 2017-11-24 | 60 |
| 2017-12-24 | 60 |
+------------+---------------+
I would try this:
SELECT SUM(records)
FROM TABLE_NAME
WHERE Date_Column >= DATEADD(MONTH, -3, GETDATE())
GROUP BY DATEPART(MONTH, Date_Column)
I found a answer
SELECT MONTHNAME(a.created_at) as tmonth, YEAR(a.created_at) as tYear,
SUM(a.credit) as credit, SUM(a.debit)
FROM telco_transactions AS a
WHERE a.telco_id = '1' and DATE(a.created_at) BETWEEN DATE(NOW())-INTERVAL 3 MONTH AND DATE(NOW())
GROUP BY MONTHNAME(a.created_at), YEAR(a.created_at);

In mysql how to select columns in a union join

How to select join table's columns when I'm using union. Specifically how to select b.id(booking id) in the following query? Also is it the right way to do it? Can you please tell me any other way to do it? I also want to select available time for a selected date if any available. I have three categories of timing.
cat1(category 1): availability on particular days of week(Example:Mon, Tue, Wed, etc of any month)
cat2(category 2): availability on First monday, second saturday, etc of any months.
cat3(category 3): availability on last saturday, last friday, etc of
any month.
I'm using day_offset, and cat columns in my doctor_schedule table to calculate date and checking it to #selected_date. I am also filtering off days with the help of my off_day table (off_days table stores information for any holidays, or if doctor taking leave for any personal reasons).
mysql> select * from doctor;
+----+-------------+
| id | name |
+----+-------------+
| 1 | John Doe |
| 2 | Larry Jones |
+----+-------------+
mysql> select * from doctor_schedule;
+----+-----------+-----+------------+----------+---------------+--------+------------+-----+
| id | doctor_id | day | start_time | end_time | booking_limit | active | day_offset | cat |
+----+-----------+-----+------------+----------+---------------+--------+------------+-----+
| 1 | 2 | 5 | 10:00:00 | 12:00:00 | 1 | 1 | 3 | 2 |
| 2 | 2 | 5 | 19:00:00 | 22:00:00 | 1 | 1 | 3 | 2 |
| 3 | 2 | 6 | 19:00:00 | 22:00:00 | 1 | 1 | 0 | 3 |
+----+-----------+-----+------------+----------+---------------+--------+------------+-----+
mysql> select * from booking;
+----+---------+-------------+--------------+------+
| id | user_id | schedule_id | booking_date | paid |
+----+---------+-------------+--------------+------+
| 1 | 1 | 3 | 2017-06-26 | 1 |
+----+---------+-------------+--------------+------+
mysql> select * from off_day;
+----+-----------+-------------+------------+
| id | doctor_id | schedule_id | date |
+----+-----------+-------------+------------+
| 2 | 1 | 3 | 2017-06-26 |
+----+-----------+-------------+------------+
set #selected_date := "2017-06-26";
set #doctor_id := 2;
SET #first_day = DATE_SUB(#selected_date, INTERVAL DAYOFMONTH(#selected_date) - 1 DAY);
select s.*
from
(select
s1.id
from doctor_schedule s1
where
s1.cat = 1
and
s1.day = weekday(#selected_date)
UNION
select
s2.id
from doctor_schedule s2
where
s2.cat = 2
and
DATE_ADD(#first_day, INTERVAL (s2.day - WEEKDAY(#first_day)) + (s2.other*7) DAY) = #selected_date
UNION
select
s3.id
from doctor_schedule s3
where
s3.cat = 3
and
date_sub(LAST_DAY(#selected_date), INTERVAL ((7 + WEEKDAY(LAST_DAY(#selected_date)) - s3.other) % 7) DAY) = #selected_date
) as s
right join
booking b
on
s.id = b.schedule_id
and
b.booking_date >= #selected_date
and
b.paid = 1
left join
off_day o
on
s.id = o.schedule_id
and
o.date = #selected_date
and
o.doctor_id = #doctor_id
where
o.schedule_id is null
group by
s.id
Mr. Tim Biegeleisen pointed that there is no booking_id in my query. Thanks to him that I found the solution. It should be b.id.
set #selected_date := "2017-06-26";
set #doctor_id := 2;
SET #first_day = DATE_SUB(#selected_date, INTERVAL
DAYOFMONTH(#selected_date) - 1 DAY);
select s.*, b.id
from
(select
s1.id
from doctor_schedule s1
where
s1.cat = 1
and
s1.day = weekday(#selected_date)
UNION
select
s2.id
from doctor_schedule s2
where
s2.cat = 2
and
DATE_ADD(#first_day, INTERVAL (s2.day - WEEKDAY(#first_day)) + (s2.other*7) DAY) = #selected_date
UNION
select
s3.id
from doctor_schedule s3
where
s3.cat = 3
and
date_sub(LAST_DAY(#selected_date), INTERVAL ((7 + WEEKDAY(LAST_DAY(#selected_date)) - s3.other) % 7) DAY) = #selected_date
) as s
right join
booking b
on
s.id = b.schedule_id
and
b.booking_date >= #selected_date
and
b.paid = 1
left join
off_day o
on
s.id = o.schedule_id
and
o.date = #selected_date
and
o.doctor_id = #doctor_id
where
o.schedule_id is null
group by
s.id

Adding new year i new column in MySQL query

I'm newbie in MySQL and I have a table which has columns
+---------------------+-------------+
| Date | Temperature |
+---------------------+-------------+
| 2016-01-01 00:00:00 | 10,1 |
| 2016-01-02 00:00:00 | 10,2 |
| ... | ... |
| 2017-01-01 00:00:00 | 12,1 |
| 2017-01-02 00:00:00 | 12,5 |
+---------------------+-------------+
I would like receive the result
+--------+------+------+
| Date | 2016 | 2017 |
+--------+------+------+
| 01 Jan | 10,1 | 12,1 |
| 02 Jan | 10,2 | 12,5 |
| ... | ... | ... |
+--------+------+------+
I wanted to use subquery, but subquery can have 1 row. Someone could help me write the correct query?
use CASE statement
SELECT DATE_FORMAT(samay, '%e %b') AS date_month,
MAX(CASE WHEN EXTRACT(YEAR FROM samay) = 2016 THEN temp END) AS '2016',
MAX(CASE WHEN EXTRACT(YEAR FROM samay) = 2017 THEN temp END) AS '2017'
FROM date_test GROUP BY date_month;
You can try something like:
select d.fdate, t1.t, t2.t
from
(select distinct month(d) as month, day(d) as day, DATE_FORMAT(d, '%e %b') as fdate from h) as d
left outer join
(select DATE_FORMAT(d, '%e %b') as fdate, t from h where year(`d`) = 2016) as t1 on (d.fdate = t1.fdate)
left outer join
(select DATE_FORMAT(d, '%e %b') as fdate, t from h where year(`d`) = 2017) as t2 on (d.fdate = t2.fdate)
order by d.month, d.day
of course change column/table names
Demo http://www.sqlfiddle.com/#!9/920ea2/2

How to join 2 query results together?

Scenario:
I have 2 query form 1 table, just want to view both query results as a single query result.
Details:
Table: loantrans
+-----+----------+---------+---------+---------+
| tid | date | account | purpose | out |
+-----+----------+---------+---------+---------+
| 1 |2014-08-12| 975 | Loan | 5000 |
| 2 |2014-08-12| 975 |Interest | 850 |
| 3 |2014-08-12| 975 | Loan | 150 |
| 4 |2014-08-12| 975 |Interest | 5000 |
+-----+----------+---------+---------+---------+
Query 1:
SELECT MONTH(`loantrans`.`date`) as month, SUM(`loantrans`.`out`) AS loanout
FROM loantrans
WHERE (`loantrans`.`date` BETWEEN '2014-01-01' AND '2014-09-20')
AND (`loantrans`.`purpose` = 'Loan')
GROUP BY MONTH(`loantrans`.`date`)
ORDER BY `loantrans`.`date`
Result:
+-------+---------+
| month | loanout |
+-------+---------+
| 1 | 28000 |
| 2 | 27000 |
| 3 | 10200 |
| 4 | 7000 |
| 5 | 95000 |
| 6 | 2000 |
+-------+---------+
Query 2:
SELECT MONTH(`loantrans`.`date`) as month, SUM(`loantrans`.`out`) AS intout
FROM loantrans
WHERE (`loantrans`.`date` BETWEEN '2014-01-01' AND '2014-09-20')
AND (`loantrans`.`purpose` = 'Interest')
GROUP BY MONTH(`loantrans`.`date`)
ORDER BY `loantrans`.`date`
Result :
+-------+---------+
| month | intout |
+-------+---------+
| 1 | 2000 |
| 2 | 750 |
| 3 | 200 |
| 4 | 180 |
| 5 | 570 |
| 6 | 625 |
+-------+---------+
What I want is like
+-------+---------+---------+
| month | intout | loanout |
+-------+---------+---------+
| 1 | 2000 | 28000 |
| 2 | 750 | 27000 |
| 3 | 200 | 10200 |
| 4 | 180 | 7000 |
| 5 | 570 | 95000 |
| 6 | 625 | 2000 |
+-------+---------+---------+
How to get result like this???
Please check this screenshot for more clear idea of what i'm looking for https://www.dropbox.com/s/dpptqb7y4c6xzi5/Capture3.PNG?dl=0
Database:
https://www.dropbox.com/s/8gbgrgvil915efr/bankdb.sql_7.zip?dl=0
SELECT MONTH(lt.date) month,
SUM((lt.purpose='Interest')*lt.out) intout,
SUM((lt.purpose='Loan')*lt.out) loanout
FROM loantrans lt
WHERE lt.date BETWEEN '2014-01-01' AND '2014-09-20'
/* AND lt.purpose IN ('Interest', 'Loan') /* If you have more purposes. */
GROUP BY month
ORDER BY month
SELECT MONTH(lt.date) month,
SUM( case when lt.purpose='Interest' then lt.out else 0 end) intout,
SUM(case when lt.purpose='Loan' then lt.out else 0 end) loanout
FROM loantrans lt
WHERE lt.date BETWEEN '2014-01-01' AND '2014-09-20'
GROUP BY month
ORDER BY month
http://sqlfiddle.com/#!2/fa8ac/5
Probably better ways to do it, but i think this works:
select coalesce(tblOne.month, tblTwo.month), intOut, loanOut
from (
SELECT MONTH(`loantrans`.`date`) as month, SUM(`loantrans`.`out`) AS loanout
FROM loantrans
WHERE (`loantrans`.`date` BETWEEN '2014-01-01' AND '2014-09-20')
AND (`loantrans`.`purpose` = 'Loan')
GROUP BY MONTH(`loantrans`.`date`)
) tblOne
left join (
SELECT MONTH(`loantrans`.`date`) as month, SUM(`loantrans`.`out`) AS intout
FROM loantrans
WHERE (`loantrans`.`date` BETWEEN '2014-01-01' AND '2014-09-20')
AND (`loantrans`.`purpose` = 'Interest')
GROUP BY MONTH(`loantrans`.`date`)
) tblTwo on tblOne.month = tblTwo.month
order by month
SELECT l1.month, l1.loanout, l2.intout FROM (
SELECT MONTH(`loantrans`.`date`) as month, SUM(`loantrans`.`out`) AS loanout
FROM loantrans
WHERE (`loantrans`.`date` BETWEEN '2014-01-01' AND '2014-09-20')
AND (`loantrans`.`purpose` = 'Loan')
GROUP BY MONTH(`loantrans`.`date`)
ORDER BY `loantrans`.`date`
) AS l1 JOIN (
SELECT MONTH(`loantrans`.`date`) as month, SUM(`loantrans`.`out`) AS intout
FROM loantrans
WHERE (`loantrans`.`date` BETWEEN '2014-01-01' AND '2014-09-20')
AND (`loantrans`.`purpose` = 'Interest')
GROUP BY MONTH(`loantrans`.`date`)
ORDER BY `loantrans`.`date`
) AS l2 ON l1.month = l2.month;
Use this with If statment
SELECT MONTH(l.date) month,
SUM(if (l.purpose='Interest' ,l.out , 0) ) intout,
SUM(if (l.purpose='Loan', l.out ,0 )) loanout
FROM loantrans l
WHERE l.date BETWEEN '2014-01-01' AND '2014-09-20'
GROUP BY month
ORDER BY month