simplify this query - mysql

SELECT COUNT( sendbook.id ) AS total, SUM( sendbook.num ) AS num, (
SELECT COUNT( sendbook.id )
FROM sendbook
INNER JOIN clients ON clients.id = sendbook.clientid
WHERE sendbook.issueid = '29'
AND clients.area >1000
AND clients.area <2000
) AS area1000, (
SELECT COUNT( sendbook.id )
FROM sendbook
INNER JOIN clients ON clients.id = sendbook.clientid
WHERE sendbook.issueid = '29'
AND clients.area >2000
AND clients.area <3000
) AS area2000, (
SELECT COUNT( sendbook.id )
FROM sendbook
INNER JOIN clients ON clients.id = sendbook.clientid
WHERE sendbook.issueid = '29'
AND clients.area >3000
AND clients.area <4001
) AS area2000
FROM `sendbook`
WHERE sendbook.issueid = '29'
total num area1000 area2000 area2000
8 438 3 3 2
Do you know a way to simplify this query?
Thinks

you need to use case statement something like this :
SELECT COUNT( sendbook.id ),
(CASE
WHEN clients.area between '1000' and '2000' THEN 1
WHEN clients.area between '2000' and '3000' THEN 2
WHEN clients.area between '3000' and '4000' THEN 3
END) AS myrange FROM mytable
GROUP BY myrange

Related

How to eleiminate NULL with 0 in sql

I have a simple table now I want when I run sql statement it should replace NULL with 0 using mysql
Here is what I have tried so far
SELECT IFNULL(targetbuttonname, 0), sessions.sid, events.datetime, count(*) as num_rows,
count(distinct sessions.sid) as sessions,
sum( targetbuttonname = 'kredyt' ) as num_kredyt,
sum(devicetype ='Computer') as num_computer from events
Now when I run my script it still returns null
Here is DEMO demo
What is wrong with my query statement?
Use COALESCE
SELECT coalesce(NULL,0), sessions.sid, events.datetime, count(*) as num_rows, count(distinct sessions.sid) as sessions,
sum( targetbuttonname = 'kredyt' ) as num_kredyt,
sum( targetbuttonname = 'konto' ) as num_konto,
sum( targetbuttonname = 'czat' ) as num_czat,
sum( targetbuttonname = 'video-voice_btns' ) as num_voice,
sum( targetbuttonname = 'video-close_btn' ) as num_close,
sum( targetbuttonname = 'video-muted_btn' ) as num_muted,
sum( targetbuttonname = 'video-play_btn' ) as num_play,
sum( targetbuttonname = 'video-pause_btn' ) as num_pause,
sum( targetbuttonname = 'video-replay_btn' ) as num_replay,
sum(watchtime) as num_watchtime,
sum(devicetype ='Computer') as num_computer from events INNER JOIN sessions ON (events.sid =sessions.sid) WHERE events.datetime BETWEEN '2019-11-11' AND '2019-11-21'
DEMO: http://sqlfiddle.com/#!9/3cf3cf/10
IFNULL will also work:
SELECT ifnull(targetbuttonname,0), sessions.sid, events.datetime, count(*) as num_rows, count(distinct sessions.sid) as sessions,
sum( targetbuttonname = 'kredyt' ) as num_kredyt,
sum( targetbuttonname = 'konto' ) as num_konto,
sum( targetbuttonname = 'czat' ) as num_czat,
sum( targetbuttonname = 'video-voice_btns' ) as num_voice,
sum( targetbuttonname = 'video-close_btn' ) as num_close,
sum( targetbuttonname = 'video-muted_btn' ) as num_muted,
sum( targetbuttonname = 'video-play_btn' ) as num_play,
sum( targetbuttonname = 'video-pause_btn' ) as num_pause,
sum( targetbuttonname = 'video-replay_btn' ) as num_replay,
sum(watchtime) as num_watchtime,
sum(devicetype ='Computer') as num_computer from events INNER JOIN sessions ON (events.sid =sessions.sid) WHERE events.datetime BETWEEN '2019-11-11' AND '2019-11-21'
Here is the DEMO: http://sqlfiddle.com/#!9/3cf3cf/14

SQL where query to a first row of IN condition

I have this SQL query:
SELECT (CASE WHEN count(_days) > 0 THEN 'yes' ELSE 'No' END) as availability
FROM (
SELECT count(roomTypeDay2.room_type_id) as _days
FROM room_type_day as roomTypeDay2
LEFT JOIN room_type as roomType2 on roomTypeDay2.room_type_id = roomType2.id
WHERE roomType2.accommodation_id=3
AND roomTypeDay2.date IN ( '2018-06-09 00:00:00','2018-06-10 00:00:00','2018-06-11 00:00:00')
GROUP BY roomTypeDay2.room_type_id
HAVING COUNT(roomTypeDay2.room_type_id) = 3
) as disponible
This works fine, but now, I want to filter if the first date row (2018-06-09 00:00:00) have
"min_night_stay <= 3 and release_days <=2"
parameters, but I don't know how doing it.
I try adding these lines to a query:
AND (roomTypeDay2.date = '2018-06-09 00:00:00' and
roomTypeDay2.min_night_stay <= 3 AND roomTypeDay2.release_days <= 2)
But this is not correct query.
UDPATE
SELECT (CASE WHEN count(_days) > 0 THEN 'yes' ELSE 'No' END) as availability
FROM (
SELECT count(roomTypeDay2.room_type_id) as _days
FROM room_type_day as roomTypeDay2
LEFT JOIN room_type as roomType2 on roomTypeDay2.room_type_id = roomType2.id
AND roomType2.accommodation_id=3
WHERE roomTypeDay2.date IN ( '2018-06-09 00:00:00','2018-06-10 00:00:00','2018-06-11 00:00:00')
GROUP BY roomTypeDay2.room_type_id
HAVING COUNT(roomTypeDay2.room_type_id) = 3
) as disponible
Solution
SELECT (CASE WHEN count(_days) > 0 THEN 'yes' ELSE 'No' END) as availability
FROM (
SELECT count(roomTypeDay2.room_type_id) as _days
FROM room_type_day as roomTypeDay2
LEFT JOIN room_type as roomType2 on roomTypeDay2.room_type_id = roomType2.id
WHERE roomType2.accommodation_id=3
AND roomTypeDay2.num_rooms_available > 0
AND (roomTypeDay2.date = '2018-06-12 00:00:00' AND roomTypeDay2.min_night_stay <= 2 AND roomTypeDay2.release_days <= 2 )
OR roomTypeDay2.date IN ( '2018-06-13 00:00:00','2018-06-14 00:00:00')
GROUP BY roomTypeDay2.room_type_id
HAVING COUNT(roomTypeDay2.room_type_id) = 3
) as disponible
This is your WHERE clause:
WHERE roomTypeDay2.date IN ('2018-06-09 00:00:00',
'2018-06-10 00:00:00',
'2018-06-11 00:00:00')
Now for the first date you want additional criteria. Use AND and ORwith parentheses for this:
WHERE
(
roomTypeDay2.date = '2018-06-09 00:00:00'
AND
roomTypeDay2.min_night_stay <= 3
AND
roomTypeDay2.release_days <= 2
)
OR
roomTypeDay2.date IN ('2018-06-10 00:00:00','2018-06-11 00:00:00')
SELECT
(
CASE WHEN count(_days) > 0 THEN 'yes' ELSE 'No' END
) as availability
from
(
SELECT
count(roomTypeDay2.room_type_id) as _days
FROM
room_type_day as roomTypeDay2
LEFT JOIN room_type as roomType2 on roomTypeDay2.room_type_id = roomType2.id
AND roomType2.accommodation_id = 3
WHERE
roomTypeDay2.date IN ('2018-06-10 00:00:00', '2018-06-11 00:00:00')
GROUP BY
roomTypeDay2.room_type_id
HAVING
COUNT(roomTypeDay2.room_type_id) = 3
union
SELECT
count(roomTypeDay2.room_type_id) as _days
FROM
room_type_day as roomTypeDay2
LEFT JOIN room_type as roomType2 on roomTypeDay2.room_type_id = roomType2.id
AND roomType2.accommodation_id = 3
WHERE
roomTypeDay2.date = '2018-06-09 00:00:00'
and roomTypeDay2.min_night_stay <= 3
AND roomTypeDay2.release_days <= 2
GROUP BY
roomTypeDay2.room_type_id
HAVING
COUNT(roomTypeDay2.room_type_id) = 3
) disponible

Combining all data with a unique ID - MySQL

I have this data that I got from my current query.
What I want to do is combine and make it a single row where the type is Senior, the cashamount and Tenderamount are the same as well.
This is my desired result:
I'm getting my data from this table:
Here's my query:
SELECT a.DATE as `DATE`, a.employee as `EMPLOYEE`, a.TYPEID, a.NAME as
`NAME`, (select (case when a.typeid = 1 then a.amount else NULL end)) as
`CASHAMOUNT`,
(select (case when a.typeid <> 1 then a.amount else NULL end)) as
`TENDERAMOUNT`, (select gndtndr.IDENT from gndtndr where gndtndr.TYPE = 12
and `gndtndr`.`CHECK`= a.CHECK and gndtndr.DATE = a.DATE) as `ID`,
from gndtndr a
where STR_TO_DATE(a.DATE, '%m/%d/%Y') BETWEEN '20170901' AND '20170901'
order by STR_TO_DATE(a.DATE, '%m/%d/%Y')
My MySQL is a bit rusty, but give this a try!
SELECT a.Date, a.Employee, a.Name, a.ID, SUM(b.Amount) AS CashAmount,
SUM(c.Amount) AS TenderAmount FROM
(SELECT DISTINCT Date, Employee, Name, ID FROM gndtndr WHERE Type = 12) AS a
LEFT JOIN gndtndr AS b
ON a.ID = b.ID AND b.TypeID = 1
LEFT JOIN gndtdr AS c
ON a.ID = c.ID and c.TypeID <> 1
GROUP BY a.Date, a.Employee, a.Name, a.ID
I've figured it out :) I just have to define the type conditions in my where clause where the type is 1(for cash).
SELECT a.DATE as `DATE`, a.employee as `EMPLOYEE`, a.TYPEID, a.NAME as
`NAME`, (select sum(gndtndr.amount) from gndtndr where gndtndr.typeid = 1
and gndtndr.`CHECK` = a.`CHECK` and gndtndr.DATE = a.DATE) as `CASHAMOUNT`,
(select (case when a.typeid <> 1 then a.amount else NULL end)) as
`TENDERAMOUNT`, (select gndtndr.IDENT from gndtndr where gndtndr.TYPE = 12
and `gndtndr`.`CHECK`= a.CHECK and gndtndr.DATE = a.DATE) as `ID` from
gndtndr a
where a.TYPEID <> 1 and STR_TO_DATE(a.DATE, '%m/%d/%Y') BETWEEN '20170901'
AND '20170901' order by STR_TO_DATE(a.DATE, '%m/%d/%Y')

MySQL IN Condition Subquery

I have a question and answers listing and an option to filter the questions based on the % of correct answers. So I am using the following query for the listing :
SELECT
question_id,
text
FROM
test_answers LEFT JOIN test_questions ON test_questions.id = test_answers.question_id
LEFT JOIN test_categories ON test_questions.`category_id` = test_categories.id
WHERE `question_id` IN(question IDS)
GROUP BY `question_id`
ORDER BY `question_id` DESC;
and using another query for finding the question IDS for which the % of correct answers in the given range. The query is as follows :
SELECT q1.question_id FROM (
SELECT test_answers.question_id AS question_id,
SUM( IF( test_answers.correct_answer =1, 1, 0 ) ) AS correct_answers,
SUM( IF( test_answers.correct_answer !=1, 1, 0 ) ) AS incorrect_answers,
round( ( SUM( IF( test_answers.correct_answer =1, 1, 0 ) ) / ( SUM( IF( test_answers.correct_answer =1, 1, 0 ) ) + SUM( IF( test_answers.correct_answer !=1, 1, 0 ) ) ) *100 ) , 2 ) AS percentage
FROM test_replies
JOIN test_answers ON test_replies.answer_id = test_answers.id
GROUP BY test_answers.question_id
HAVING percentage between 80 and 89 AND correct_answers >25
) AS q1
Now the issue is that the second query returns almost 4000 question Ids and it will increase in the near future and might be become 10k or more. So I seriously would like to optimize the query as it is going to impact the performance in a great deal. Can anyone suggest a better method for doing it ?
try join instead of IN, see if it helps. (sql not tested)
SELECT
ta.question_id, text
FROM
(
SELECT test_answers.question_id AS question_id,
SUM( IF( test_answers.correct_answer =1, 1, 0 ) ) AS correct_answers,
SUM( IF( test_answers.correct_answer !=1, 1, 0 ) ) AS incorrect_answers,
round( ( SUM( IF( test_answers.correct_answer =1, 1, 0 ) ) / ( SUM( IF( test_answers.correct_answer =1, 1, 0 ) ) + SUM( IF( test_answers.correct_answer !=1, 1, 0 ) ) ) *100 ) , 2 ) AS percentage
FROM test_replies
JOIN test_answers ON test_replies.answer_id = test_answers.id
GROUP BY test_answers.question_id
HAVING percentage between 80 and 89 AND correct_answers >25
) AS q1
INNER JOIN
test_answers ta USING (question_id)
LEFT JOIN
test_questions ON test_questions.id = ta.question_id
LEFT JOIN
test_categories ON test_questions.`category_id` = test_categories.id
GROUP BY
ta.question_id`
ORDER BY
ta.question_id DESC;

Multiple sum in SQL query

SELECT sum( plot_status = 'OPEN' ) AS OPEN
, sum( plot_status = 'SOLD' ) AS SOLD
FROM `tbl_plot`
GROUP BY `plot_status
This is giving
OPEN SOLD
7 0
0 8
How to make it
OPEN SOLD
7 8
Or is it possible?
just remove the GROUP BY clause and it will work.
SELECT sum( plot_status = 'OPEN' ) AS `OPEN` ,
sum( plot_status = 'SOLD' ) AS SOLD
FROM `tbl_plot`
If there is present plot_name or id then group by that not by plot_status:
SELECT sum( plot_status = 'OPEN' ) AS
OPEN , sum( plot_status = 'SOLD' ) AS SOLD
FROM `tbl_plot`
GROUP BY //`plot_name or plot_id
This will work for you for individual plot.
And if you don't want that then remove the group by clause.
select * from
(
select sum( plot_status = 'OPEN' FROM tbl_plot ) AS OPEN
select sum( plot_status = 'SOLD' FROM tbl_plot ) As Sold
)tbl