Mysql Use of MAX in a subquery - mysql

Why can't I use that subquery which returns a group error ?
SELECT hs.dateFin, hs.codeAdherent, hs.codeArticle
FROM hs
WHERE hs.codeFamilleArticle IN ('CNI', 'COT', 'ABO', 'ABOW',
'CNIW', 'O&T', 'EPH', 'TAX')
AND codeAdherent != 0
AND MAX(hs.dateFin) BETWEEN '2017-01-01'
AND '2017-12-31'
GROUP BY hs.codeAdherent
The same data exists for 2018-01-01 and 2018-12-31 but I only want to get the ones that end in 2017.
Here under a sample of table which contains 140000 raws (not all columns are showed).
codeAdherent A has data for 2018, 2017, 2016.
codeAdherent B has data for2018, 2017
codeAdherent C only for 2017.
If I do a select on 2017 I get all three codeAdherent, then the MAX BETWEEN will exclude A and B... But that's doesn't work

You can use NOT EXISTS to check if no record exists for 2018:
SELECT dateFin, codeAdherent, codeArticle
FROM hs AS t
WHERE codeFamilleArticle IN ('CNI', 'COT', 'ABO', 'ABOW', 'CNIW', 'O&T', 'EPH', 'TAX')
AND codeAdherent != 0
-- filter 2017 rows
AND dateFin >= '2017-01-01'
AND dateFin < '2018-01-01'
-- filter rows where 2018 data does not exist
AND NOT EXISTS (
SELECT 1
FROM hs
WHERE codeAdherent = t.codeAdherent
AND dateFin >= '2018-01-01'
)

You can do it like this:
HAVING YEAR(MAX(hs.dateFin)) = 2017

You cannot use aggregate functions like Max() inside Where clause. You can simply modify your where condition to include dates in year 2017 only, and then determine Max() date after group by.
SELECT MAX(hs.dateFin), hs.codeAdherent, hs.codeArticle
FROM hs
WHERE hs.codeFamilleArticle IN ('CNI', 'COT', 'ABO', 'ABOW',
'CNIW', 'O&T', 'EPH', 'TAX')
AND hs.codeAdherent != 0
WHERE hs.dateFin BETWEEN '2017-01-01'
AND '2017-12-31'
GROUP BY hs.codeAdherent, hs.codeArticle

Related

Trying to group query by hours

Trying to group my query by hours and have a '0' if nothing is found.
SELECT
tmhours.hours_value,
COALESCE(cc.countingSheep,0) AS countingSheep
FROM time_hours as tmhours
LEFT JOIN (
SELECT count(*) as countingSheep, company_id, `sales_date`
FROM tbl_cc
WHERE `sales_date` BETWEEN '2019-05-01 00:00:00' AND '2019-05-01 23:59:59' AND company_id = '12345' ) as cc on date_format(sales_date, '%H') = tmhours.hours_value
GROUP BY tmhours.hours_value
The time_hours table just contains 01,02,03,04 .... 22, 23
Based on the above query, I am just getting 0's until 07
So:
01 0
02 0
03 0
04 0
05 0
06 0
07 - 57 (the first match in the DB is 07:14:35) - the 57 is the total count, it's not grouping results
08 0
09 0
...
...
22 0
23 0
I've tried removing the group by inside the inner select, tried moving the date_format = hours_value.
Your problem is that you're not grouping the subquery data by the hour, so your subquery is only returning one row (since it has a COUNT in it). Add grouping to the subquery and it should work fine. Note that you don't need grouping in the outer query as you're not doing any aggregation. Also, since you only want one day's data, you can simplify your WHERE condition using the DATE function.
SELECT
tmhours.hours_value,
COALESCE(cc.countingSheep,0) AS countingSheep
FROM time_hours as tmhours
LEFT JOIN (
SELECT count(*) as countingSheep, date_format(sales_date, '%H') AS sales_hour
FROM tbl_cc
WHERE DATE(`sales_date`) = '2019-05-01' AND company_id = '12345'
GROUP BY sales_hour) as cc ON sales_hour = tmhours.hours_value
You have not aggregated function in the outer query so If you need distinct result use DISTINCT (group by can produce unexpected result ) but in your case seems not necessary
insteadd you missed the group by based on the hour in the inner join
SELECT
tmhours.hours_value,
COALESCE(cc.countingSheep,0) AS countingSheep
FROM time_hours as tmhours
LEFT JOIN ( SELECT count(*) as countingSheep, company_id, date_format(sales_date, '%H')
FROM tbl_cc
WHERE `sales_date` BETWEEN '2019-05-01 00:00:00' AND '2019-05-01 23:59:59'
AND company_id = '12345'
GROUP BY company_id , date_format(sales_date, '%H')
) as cc on date_format(sales_date, '%H') = tmhours.hours_value

I want to show data monthwise in one sql query? Is it possible in mysql

I have a one database and saved one year data. I want to access all data in monthwise. like (01-01-2017-01-30-2017). My column type Datetime
date_table
01-01-2016
01-02-2016
02-02-2017
.....
.....
I Want to show
date_table count
01-01-2016 to 30-01-2016 5
01-02-2016 t0 28-02-2016 10
Have a derived table that returns the year and month. GROUP BY its result and count:
select y, m, count(*)
from
(
select year(date_column) y , month(date_column) m
from tablename
)
group by y, m
I don't know MySQL very well, so you'll have to format the output by yourself.
You can use mysql's built in function LAST_DAY, like this:
Just replace here "t", with your table name
SELECT CONCAT( CONCAT(mnth, '-01'), ' to ', LAST_DAY(CONCAT(mnth, '-01')) ) AS date_table, cnt FROM (
select substr(cast(date_table as CHAR), 1, 7) AS mnth, count(*) AS cnt from t
group by substr(cast(date_table as CHAR), 1, 7)
) outertable
If your Date is of type DateTime in SQL-Server
SELECT DATENAME(MONTH,TimeStamp) AS [MONTH]
, DATEPART(YY,TimeStamp) [YEAR]
, SUM(*) Count
FROM Table
WHERE TimeStamp IS NOT NULL
GROUP BY DATENAME(MONTH,TimeStamp), DATEPART(YY,TimeStamp)
Result would be like this
MONTH YEAR Count
December2015 237
October 2015 51
August 2016 0
January 2016 9
March 2016 160

using <= or >= in timestamp field in mysql

I would like to select all records before 2014-03-22 date:
where date < 2014-03-22 // what I need
but below code doesn't see 2013 year's records :
SELECT * FROM `tractions` WHERE YEAR(date) <= 2014 AND MONTH(date) <= 3 and DAY(date) <= 22 and succ = 1
Is there anything wrong with:
SELECT * FROM tractions
WHERE date < '2014-03-22' -- place the date, correctly formatted, in quotes
Since this comparison doesn't use any functions, it will also allow you to use any indices setup on the date column.

mysql - filter query result based on count of one column's value?

I am running the following mysql query:
SELECT visitnum, userid
FROM user_visit
WHERE date >= '2015-10-31 00:00:00' AND date <= '2015-11-01 23:59:59'
Which returns me the following results:
visitnum userid
2010 60265
2011 60264
2012 60264
2013 60268
2014 60269
2015 60269
2016 60269
As you can see, this means the user 60265 and 60268 has one visit; user 60264 has two visits and user 60269 has three visits.
Now - how do I modify my mysql query so that it returns me only the rows associated with users that only visit ONCE? In other words, I expect my query to return me the following result:
visitnum userid
2010 60265
2013 60268
And how do I modify the query to return me only the rows that associated with users that only visit TWICE? like this:
visitnum userid
2011 60264
2012 60264
SELECT visitnum, userid
FROM user_visit
WHERE userid IN (
SELECT userid
FROM user_visit
WHERE date >= '2015-10-31 00:00:00' AND date <= '2015-11-01 23:59:59'
GROUP BY userid
HAVING COUNT(*) = 2
)
You can use this trick:
SELECT max(visitnum) as visitnum, userid
FROM user_visit
WHERE date >= '2015-10-31 00:00:00' AND date <= '2015-11-01 23:59:59'
GROUP BY usserid
HAVING COUNT(*) = 1;
The trick here is that MAX(visitnum) is the one-and-only visit number, when there is only one row in the group.
An alternative way that doesn't use GROUP BY is:
select uv.*
from user_visits uv
where not exists (select 1
from user_visits uv2
where uv2.userid = uv.userid and uv.visitnum <> uv2.visitnum
);
This should have better performance, if you have in an index on user_visits(userid, visitnum).

Query with sum case group by

I am facing problem with following query:
SELECT sum(CASE WHEN status.new_reg_yn='n'
AND month(status.visit_date)-1 = 8
AND year(status.visit_date) = 2015 THEN 1 ELSE 0 END)
FROM customer_visit_status_tbl status,
customer_details_tbl cust
WHERE status.customer_id = cust.customer_id
AND cust.client_id=65
GROUP BY status.customer_id
The problem is that this query is returning results for customer with same id though I used group by. For example, in the month of September, if same customer visits 5 times it is returning count as 5 instead of 1 though I used group by.
It is really unclear what you want... Yes, distinct customers for a given time period, but then you are taking the month of the date visited -1 and looking for that equal to 8. Being that current month is 9 (September), Are you just looking for those based on activity the month prior to whatever the current is? So, for example, if Sept, 2015, you want totals for Aug, 2015. In Jan, 2016, you would want Dec, 2015? If that is the case, you can use the current date to subtract 1 month and get that as basis of the query. Then you can have your additional specific client (65 in this case).
My (subselect sqlvars) pre-creates variables applied for the query. It computes one month ago by subtracting 1 month from whatever the current date it. Then uses that as basis of the month representing whatever was the prior month, and similarly for that respective year.
Since this will in essence create a single row return, there is no Cartesian result and you can just run with your original other tables for final counts.
select
count( distinct s.customer_id ) as UniqueCustomers
from
( select #oneMonthAgo := DATE_ADD(CURRENT_DATE, INTERVAL -1 MONTH),
#finalMonth := MONTH( #oneMonthAgo ),
#finalYear := YEAR( #oneMonthAgo ) sqlvars,
customer_visit_status_tbl s
JOIN customer_details_tbl c
on s.customer_id = c.customer_id
AND c.client_id = 65
where
s.new_reg_yn='n'
Update Ans -
Select count(*)
from
( SELECT distinct status.customer_id
FROM customer_visit_status_tbl status
, customer_details_tbl cust
WHERE status.customer_id = cust.customer_id
AND cust.client_id = 65
and status.new_reg_yn = 'n'
AND month(status.visit_date)-1 = 8
AND year(status.visit_date) = 2015
) customer_visited