Mysql query - find sum not in multiple range (Evergreen) - mysql

I need to fetch some data from mySql evergreen period (total - some prmo periods) ;
SELECT SUM(view) AS tUniquePageViews FROM store_report_per_day WHERE tpi = 'SE0541' AND YEAR(trxDate) = '2018'
Total : 462
SELECT SUM(view) AS tUniquePageViews FROM store_report_per_day WHERE tpi = 'SE0541' AND trxDate >= '2017-03-03' AND trxDate <= '2017-09-12'
0
SELECT SUM(view) AS tUniquePageViews FROM store_report_per_day WHERE tpi = 'SE0541' AND trxDate >= '2018-09-11' AND trxDate <= '2019-01-03'
5
SELECT SUM(view) AS tUniquePageViews FROM store_report_per_day WHERE tpi = 'SE0541' AND trxDate >= '2018-07-01' AND trxDate <= '2018-09-04'
218
SELECT SUM(view) AS tUniquePageViews FROM store_report_per_day WHERE tpi = 'SE0541' AND trxDate >= '2018-08-01' AND trxDate <= '2018-08-18'
4
SELECT SUM(view) AS tUniquePageViews FROM store_report_per_day WHERE tpi = 'SE0541' AND trxDate >= '2018-07-01' AND trxDate <= '2018-07-31'
4
SELECT SUM(view) AS tUniquePageViews FROM store_report_per_day WHERE tpi = 'SE0541' AND trxDate >= '2018-06-15' AND trxDate <= '2018-06-30'
2
Now I need to fetch Total - (All periods) My query is
SELECT SUM(view) AS tUniquePageViews FROM store_report_per_day WHERE tpi = 'SE0541' AND 1 AND (trxDate < '2018-09-11' OR trxDate > '2018-10-25') AND (trxDate < '2018-07-01' OR trxDate > '2018-09-04') AND (trxDate < '2018-08-01' OR trxDate > '2018-08-18') AND (trxDate < '2018-07-01' OR trxDate > '2018-07-31') AND (trxDate < '2018-06-15' OR trxDate > '2018-06-30')
My desired Output is
462-0-5-218-4-4-2 = 229 But i am getting 237
When I hit queries for 1 or 2 date range it show fine result but all together not.
What is the issue in my query.

Why not just union all your queries together to get the final sum?
SELECT SUM(tUniquePageViews) FROM
(
SELECT SUM(view) AS tUniquePageViews FROM store_report_per_day WHERE tpi = 'SE0541' AND YEAR(trxDate) = '2018'
union all
SELECT SUM(view) AS tUniquePageViews FROM store_report_per_day WHERE tpi = 'SE0541' AND trxDate >= '2017-03-03' AND trxDate <= '2017-09-12'
union all
SELECT SUM(view) AS tUniquePageViews FROM store_report_per_day WHERE tpi = 'SE0541' AND trxDate >= '2018-09-11' AND trxDate <= '2019-01-03'
union all
SELECT SUM(view) AS tUniquePageViews FROM store_report_per_day WHERE tpi = 'SE0541' AND trxDate >= '2018-07-01' AND trxDate <= '2018-09-04'
union all
SELECT SUM(view) AS tUniquePageViews FROM store_report_per_day WHERE tpi = 'SE0541' AND trxDate >= '2018-08-01' AND trxDate <= '2018-08-18'
union all
SELECT SUM(view) AS tUniquePageViews FROM store_report_per_day WHERE tpi = 'SE0541' AND trxDate >= '2018-07-01' AND trxDate <= '2018-07-31'
union all
SELECT SUM(view) AS tUniquePageViews FROM store_report_per_day WHERE tpi = 'SE0541' AND trxDate >= '2018-06-15' AND trxDate <= '2018-06-30'
) a;

You can try using conditional aggregation
SELECT
SUM(case when YEAR(trxDate) = '2018' then view end)-
SUM(case when trxDate >= '2017-03-03' AND trxDate <= '2017-09-12' then view end) -
SUM(case when trxDate >= '2018-09-11' AND trxDate <= '2019-01-03' then view end)-
SUM(case when trxDate >= '2018-07-01' AND trxDate <= '2018-09-04' then view end)-
SUM(case when trxDate >= '2018-08-01' AND trxDate <= '2018-08-18' then view end)-
SUM(case when trxDate >= '2018-07-01' AND trxDate <= '2018-07-31' then view end)-
SUM(case when trxDate >= '2018-06-15' AND trxDate <= '2018-06-30' then view end)
AS tUniquePageViews
FROM store_report_per_day WHERE tpi = 'SE0541'

Related

Combine multiple OR LIKE statements without invalidating other filters [duplicate]

i have this MySQL query:
SELECT * FROM forex_pair_signals AS SENALES
JOIN forex_pair_price AS PRECIO
ON SENALES.forex_pair_price_id = PRECIO.forex_pair_price_id
JOIN forex_pair AS PARES
ON PRECIO.forex_pair_id = PARES.forex_pair_id
WHERE
PRECIO.forex_pair_price_time >= '2019-02-01 00:00' AND
PRECIO.forex_pair_price_time <= '2019-02-07 01:00' AND
TIME (PRECIO.forex_pair_price_time) BETWEEN '06:00' AND '13:00' AND
PARES.forex_pair_id = 13 AND SENALES.forex_pair_signals_result = 1 AND
PRECIO.forex_pair_price_rsi >= '80.00'
OR PRECIO.forex_pair_price_rsi <= '20.00'
ORDER BY SENALES.forex_pair_signals_id DESC
This query works fine except when add the following filter:
AND PRECIO.forex_pair_price_rsi >= '80.00' OR
PRECIO.forex_pair_price_rsi <= '20.00'
The problem is that the last filter do ignores all other filters and the result is get all data that does comply with the last filter.
AND is evaluated before OR because AND has a higher precedence. Use parentheses to override the operator precendence:
WHERE
PRECIO.forex_pair_price_time >= '2019-02-01 00:00' AND
PRECIO.forex_pair_price_time <= '2019-02-07 01:00' AND
TIME (PRECIO.forex_pair_price_time) BETWEEN '06:00' AND '13:00' AND
PARES.forex_pair_id = 13 AND SENALES.forex_pair_signals_result = 1 AND
(
PRECIO.forex_pair_price_rsi >= '80.00'
OR
PRECIO.forex_pair_price_rsi <= '20.00'
)
Or you could rewrite your condition so it's just one expression:
PRECIO.forex_pair_price_rsi not between '20.01' and '79.99'
Operator precedence
When you use more than one logical operator in an expression, MySQL evaluates the OR operators after the AND operators. This is called operator precedence.1
SELECT true OR false AND false;
Result
true OR false AND false
-----------------------
1
SELECT (true OR false) AND false;
Result
(true OR false) AND false
-------------------------
0
thus you need parantheses for such case
WHERE
PRECIO.forex_pair_price_time >= '2019-02-01 00:00' AND
PRECIO.forex_pair_price_time <= '2019-02-07 01:00' AND
TIME (PRECIO.forex_pair_price_time) BETWEEN '06:00' AND '13:00' AND
PARES.forex_pair_id = 13 AND SENALES.forex_pair_signals_result = 1 AND
(
PRECIO.forex_pair_price_rsi >= '80.00' OR
PRECIO.forex_pair_price_rsi <= '20.00'
)
I think I would try to tidy up the query by consolidating the ranged logic in the WHERE clause.
SELECT *
FROM forex_pair_signals AS senales
INNER JOIN forex_pair_price AS precio ON senales.forex_pair_price_id = precio.forex_pair_price_id
INNER JOIN forex_pair AS pares ON precio.forex_pair_id = pares.forex_pair_id
WHERE pares.forex_pair_id = 13
AND senales.forex_pair_signals_result = 1
AND precio.forex_pair_price_time BETWEEN '2019-02-01 00:00' AND '2019-02-07 01:00'
AND precio.forex_pair_price_rsi NOT BETWEEN '20.00' AND '80.00'
AND TIME(precio.forex_pair_price_time) BETWEEN '06:00' AND '13:00'
ORDER BY senales.forex_pair_signals_id DESC
Your final WHERE clause condition can be rewritten as NOT BETWEEN which totally avoids the issue.
I also took the liberty to make your table aliases lowercase and I rearranged the WHERE clause conditions to position the simpler/lighter conditions first.
I think this query is much tidier now.
(p.s. Try to avoid using * in your SELECT claues; you should only ask for data that you intend to use.)
You should use parenthesis while using OR function, as it corresponds to either one or two WHERE Clause defined within it by differentiating in brackets.
SELECT * FROM forex_pair_signals AS SENALES
JOIN forex_pair_price AS PRECIO
ON SENALES.forex_pair_price_id = PRECIO.forex_pair_price_id
JOIN forex_pair AS PARES
ON PRECIO.forex_pair_id = PARES.forex_pair_id
WHERE
PRECIO.forex_pair_price_time >= '2019-02-01 00:00' AND
PRECIO.forex_pair_price_time <= '2019-02-07 01:00' AND
TIME (PRECIO.forex_pair_price_time) BETWEEN '06:00' AND '13:00' AND
PARES.forex_pair_id = 13 AND SENALES.forex_pair_signals_result = 1 AND
(PRECIO.forex_pair_price_rsi >= '80.00'
OR PRECIO.forex_pair_price_rsi <= '20.00')
ORDER BY SENALES.forex_pair_signals_id DESC;

Why query returns empty result set without LIMIT clause?

I have this mysql function:
BEGIN
DECLARE top_tags VARCHAR(100) charset utf8;
SELECT substring_index(group_concat(x.NAME order BY x.tag_score DESC separator ','), ',', 5)
INTO top_tags
FROM (SELECT t.NAME, Sum(r.score) AS tag_score
FROM reputations r
JOIN qanda_tags qt ON qt.qanda_id = r.question_id
JOIN tags t ON t.id = qt.tag_id
WHERE r.owner_id = 1
AND r.date_time > CASE 'all'
WHEN 'WEEK' THEN unix_timestamp(date_sub(Now(), interval 1 week))
WHEN 'MONTH' THEN unix_timestamp(date_sub(now(), interval 1 month))
WHEN 'YEAR' THEN unix_timestamp(date_sub(now(), interval 1 year))
ELSE 1
END
group BY t.NAME ) x;
return top_tags;
end
It returns an empty result set:
And when I add limit 60 clause right after group BY t.NAME, it returns the expected result:
Why really?
Note: limit 61 or more causes no result either. limit 60 or less has the result.
I'm not sure, but would it be more efficient to do the filtering before the group_concat()?
SELECT group_concat(x.NAME order BY x.tag_score DESC separator ',')
INTO top_tags
FROM (SELECT t.NAME, Sum(r.score) AS tag_score
FROM reputations r JOIN
qanda_tags qt
ON qt.qanda_id = r.question_id JOIN
tags t
ON t.id = qt.tag_id
WHERE r.owner_id = 1 AND
r.date_time > (CASE 'all'
WHEN 'WEEK' THEN unix_timestamp(date_sub(Now(), interval 1 week))
WHEN 'MONTH' THEN unix_timestamp(date_sub(now(), interval 1 month))
WHEN 'YEAR' THEN unix_timestamp(date_sub(now(), interval 1 year))
ELSE 1
END)
group BY t.NAME
order by tag_score desc
limit 5
) x;

Comparison operator is not working in MySQL query

i have this MySQL query:
SELECT * FROM forex_pair_signals AS SENALES
JOIN forex_pair_price AS PRECIO
ON SENALES.forex_pair_price_id = PRECIO.forex_pair_price_id
JOIN forex_pair AS PARES
ON PRECIO.forex_pair_id = PARES.forex_pair_id
WHERE
PRECIO.forex_pair_price_time >= '2019-02-01 00:00' AND
PRECIO.forex_pair_price_time <= '2019-02-07 01:00' AND
TIME (PRECIO.forex_pair_price_time) BETWEEN '06:00' AND '13:00' AND
PARES.forex_pair_id = 13 AND SENALES.forex_pair_signals_result = 1 AND
PRECIO.forex_pair_price_rsi >= '80.00'
OR PRECIO.forex_pair_price_rsi <= '20.00'
ORDER BY SENALES.forex_pair_signals_id DESC
This query works fine except when add the following filter:
AND PRECIO.forex_pair_price_rsi >= '80.00' OR
PRECIO.forex_pair_price_rsi <= '20.00'
The problem is that the last filter do ignores all other filters and the result is get all data that does comply with the last filter.
AND is evaluated before OR because AND has a higher precedence. Use parentheses to override the operator precendence:
WHERE
PRECIO.forex_pair_price_time >= '2019-02-01 00:00' AND
PRECIO.forex_pair_price_time <= '2019-02-07 01:00' AND
TIME (PRECIO.forex_pair_price_time) BETWEEN '06:00' AND '13:00' AND
PARES.forex_pair_id = 13 AND SENALES.forex_pair_signals_result = 1 AND
(
PRECIO.forex_pair_price_rsi >= '80.00'
OR
PRECIO.forex_pair_price_rsi <= '20.00'
)
Or you could rewrite your condition so it's just one expression:
PRECIO.forex_pair_price_rsi not between '20.01' and '79.99'
Operator precedence
When you use more than one logical operator in an expression, MySQL evaluates the OR operators after the AND operators. This is called operator precedence.1
SELECT true OR false AND false;
Result
true OR false AND false
-----------------------
1
SELECT (true OR false) AND false;
Result
(true OR false) AND false
-------------------------
0
thus you need parantheses for such case
WHERE
PRECIO.forex_pair_price_time >= '2019-02-01 00:00' AND
PRECIO.forex_pair_price_time <= '2019-02-07 01:00' AND
TIME (PRECIO.forex_pair_price_time) BETWEEN '06:00' AND '13:00' AND
PARES.forex_pair_id = 13 AND SENALES.forex_pair_signals_result = 1 AND
(
PRECIO.forex_pair_price_rsi >= '80.00' OR
PRECIO.forex_pair_price_rsi <= '20.00'
)
I think I would try to tidy up the query by consolidating the ranged logic in the WHERE clause.
SELECT *
FROM forex_pair_signals AS senales
INNER JOIN forex_pair_price AS precio ON senales.forex_pair_price_id = precio.forex_pair_price_id
INNER JOIN forex_pair AS pares ON precio.forex_pair_id = pares.forex_pair_id
WHERE pares.forex_pair_id = 13
AND senales.forex_pair_signals_result = 1
AND precio.forex_pair_price_time BETWEEN '2019-02-01 00:00' AND '2019-02-07 01:00'
AND precio.forex_pair_price_rsi NOT BETWEEN '20.00' AND '80.00'
AND TIME(precio.forex_pair_price_time) BETWEEN '06:00' AND '13:00'
ORDER BY senales.forex_pair_signals_id DESC
Your final WHERE clause condition can be rewritten as NOT BETWEEN which totally avoids the issue.
I also took the liberty to make your table aliases lowercase and I rearranged the WHERE clause conditions to position the simpler/lighter conditions first.
I think this query is much tidier now.
(p.s. Try to avoid using * in your SELECT claues; you should only ask for data that you intend to use.)
You should use parenthesis while using OR function, as it corresponds to either one or two WHERE Clause defined within it by differentiating in brackets.
SELECT * FROM forex_pair_signals AS SENALES
JOIN forex_pair_price AS PRECIO
ON SENALES.forex_pair_price_id = PRECIO.forex_pair_price_id
JOIN forex_pair AS PARES
ON PRECIO.forex_pair_id = PARES.forex_pair_id
WHERE
PRECIO.forex_pair_price_time >= '2019-02-01 00:00' AND
PRECIO.forex_pair_price_time <= '2019-02-07 01:00' AND
TIME (PRECIO.forex_pair_price_time) BETWEEN '06:00' AND '13:00' AND
PARES.forex_pair_id = 13 AND SENALES.forex_pair_signals_result = 1 AND
(PRECIO.forex_pair_price_rsi >= '80.00'
OR PRECIO.forex_pair_price_rsi <= '20.00')
ORDER BY SENALES.forex_pair_signals_id DESC;

issue combining two mysql queries

I have two queries I am looking to combine into one. This query will be called by backbone in a rails app. The final result should look like this. Thanks in advance.
Title Impressions Completed
Test 1234 500 34
SELECT title, count(*) as impressions FROM `stats`
WHERE `stats`.`user_id` = 2
AND (stats.event ='play' and videopos = '0')
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59')
GROUP BY title;
SELECT title, count(*) as completed FROM `stats`
WHERE `stats`.`user_id` = 2
AND (stats.event ='completed')
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59')
GROUP BY title;
try that :
SELECT title,(select count(*) FROM `stats` WHERE stats.event ='play' and videopos = '0' AND `stats`.`user_id` = 2 AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59') ) as impressions ,(select count(*) FROM `stats` WHERE stats.event ='completed' AND `stats`.`user_id` = 2 AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59') ) as completed
FROM `stats`
WHERE `stats`.`user_id` = 2
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59')
GROUP BY title;
If you just want to combine the result, use UNION/UNION ALL
SELECT title, count(*) as impressions FROM `stats`
WHERE `stats`.`user_id` = 2
AND (stats.event ='play' and videopos = '0')
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59')
GROUP BY title
UNION
SELECT title, count(*) as completed FROM `stats`
WHERE `stats`.`user_id` = 2
AND (stats.event ='completed')
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59')
GROUP BY title;
Try this :
SELECT title,
Sum(Case When `stats`.`user_id` = 2
AND (stats.event ='play' and videopos = '0')
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59' Then 1 Else 0 End)
as impressions ,
Sum(Case When `stats`.`user_id` = 2
AND (stats.event ='completed')
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59') Then 1 Else 0 End)
as completed
FROM `stats`
WHERE (`stats`.`user_id` = 2
AND (stats.event ='play' and videopos = '0')
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59') )
OR
(`stats`.`user_id` = 2
AND (stats.event ='completed')
AND (date_time between '2014-03-08 00:00:00' and '2014-03-15 23:59:59') )
GROUP BY title;
btw, I am coming from ms-sql-server background but I checked on mysql case when syntax. And I typed in notepad, so untested. But I hope you catch the Sum Case When 1 0 idea and tweak it to your requirement..
I figured it out. This worked for me.
SELECT s.date as date, s.title as title,
count(F.id) as impressions,
count(D.event) as completed
FROM stats s
Left Join stats as F on s.id = F.id and F.event ='play' and F.videopos = '0'
Left Join stats as D on s.id = D.id and D.event = 'completed'
WHERE s.user_id = '2'
AND (s.date_time between '2014-03-08 00:00:00' and '2014-03-18 23:59:59')
AND s.title is not null
GROUP BY s.title

MySQL: Selecting available vehicles that are not reserved

I have the following two records in the reservation table of a MySQL database.
When I use this query to get the vehicles that are available, it seems to give me every vehicle instead of just the ones not in the reservation table between the specified dates.
this is the query:
SELECT v.id, v.brand, v.type, v.description, v.airco, v.seats, v.hourly_rent
FROM vehicle as v
WHERE v.id
NOT IN(
(SELECT v.id
FROM vehicle as v
LEFT JOIN reservation as r on r.`vehicle_id` = v.id
WHERE r.status_id in(3,4,5)
AND (
(
('2014-01-01' >= r.startdate AND '2014-01-03' <= r.enddate )
OR
('2014-01-01' <= r.startdate AND '2014-01-03' >= r.enddate )
)
OR
(
('2014-01-01' >= r.startdate AND '2014-01-01' <= r.enddate)
OR
('2014-01-03' >= r.startdate AND '2014-01-03' <= r.enddate)
)
)
GROUP BY v.id
)
)
And when I use this query:
SELECT *
FROM reservation as r
WHERE (
(
('2014-01-01' >= r.startdate AND '2014-01-03' <= r.enddate )
OR
('2014-01-01' <= r.startdate AND '2014-01-03' >= r.enddate )
)
OR
(
('2014-01-01' >= r.startdate AND '2014-01-01' <= r.enddate)
OR
('2014-01-03' >= r.startdate AND '2014-01-03' <= r.enddate)
)
)
To get the reservations only, I get 1 record as u can see in the picture.
What could be wrong and how can I fix this?
Try This -
SELECT v.id, v.brand, v.type, v.description, v.airco, v.seats, v.hourly_rent
FROM vehicle AS v
LEFT JOIN reservation AS r
ON v.id = r.vehicle_id
AND r.startdate <= '2014-01-03'
AND r.enddate >= '2014-01-01'
WHERE r.id IS NULL;
Or with your status entries
SELECT v.id, v.brand, v.type, v.description, v.airco, v.seats, v.hourly_rent
FROM vehicle AS v
LEFT JOIN reservation AS r
ON v.id = r.vehicle_id
AND r.startdate <= '2014-01-03'
AND r.enddate >= '2014-01-01'
AND r.status NOT IN (3,4,5)
WHERE r.id IS NULL;
Without seeing the table structure it's harder to assume however this is my crack.
Just look where the V.id not exeists int the reservation table.
SELECT
v.id,
v.brand,
v.type,
v.description,
v.airco,
v.seats,
v.hourly_rent
FROM vehicle as v
WHERE NOT EXISTS (
SELECT 1
FROM reservation as r
WHERE r.vehicle_id = v.id
AND r.status_id NOT IN (3,4,5)
AND(
(
('2014-01-01' >= r.startdate AND '2014-01-03' <= r.enddate )
OR
('2014-01-01' <= r.startdate AND '2014-01-03' >= r.enddate )
)
OR
(
('2014-01-01' >= r.startdate AND '2014-01-01' <= r.enddate)
OR
('2014-01-03' >= r.startdate AND '2014-01-03' <= r.enddate)
)
)
)
GROUP BY v.id))