SQL: Can GROUP BY contain an expression as a field? - sql

I want to group a set of dated records by year, when the date is to the day. Something like:
SELECT venue, YEAR(date) AS yr, SUM(guests) AS yr_guests
FROM Events
...
GROUP BY venue, YEAR(date);
The above is giving me results instead of an error, but the results are not grouping by year and venue; they do not appear to be grouping at all.
My brute force solution would be a nested subquery: add the YEAR() AS yr as an extra column in the subquery, then do the grouping on yr in the outer query. I'm just trying to learn to do as much as possible without nesting, because nesting usually seems horribly inefficient.
I would tell you the exact SQL implementation I'm using, but I've had trouble discovering it. (I'm working through the problems on http://www.sql-ex.ru/ and if you can tell what they're using, I'd love to know.) Edited to add: Per test in comments, it is probably not SQL Server.
Edited to add the results I am getting (note the first two should be summed):
venue | yr | yr_guests
1 2012 15
1 2012 35
2 2012 12
1 2008 15
I expect those first two lines to instead be summed as
1 2012 50

Works Fine in SQL Server 2008.
See working Example here: http://sqlfiddle.com/#!3/3b0f9/6
Code pasted Below.
Create The Events Table
CREATE TABLE [Events]
( Venue INT NOT NULL,
[Date] DATETIME NOT NULL,
Guests INT NOT NULL
)
Insert the Rows.
INSERT INTO [Events] VALUES
(1,convert(datetime,'2012'),15),
(1,convert(datetime,'2012'),35),
(2,convert(datetime,'2012'),12),
(1,convert(datetime,'2008'),15);
GO
-- Testing, select newly inserted rows.
--SELECT * FROM [Events]
--GO
Run the GROUP BY Sql.
SELECT Venue, YEAR(date) AS yr, SUM(guests) AS yr_guests
FROM Events
GROUP BY venue, YEAR(date);
See the Output Results.
VENUE YR YR_GUESTS
1 2008 15
1 2012 50
2 2012 12

it depends of your database engine (or SQL)
to be sure (over different DB Systems & Versions), make a subquery
SELECT venue, theyear, SUM(guests) from (
SELECT venue, YEAR(date) AS theyear, guest
FROM Events
)
GROUP BY theyear
you make a subtable of
venue, date as theyear, guest
aaaa, 2001, brother
aaaa, 2001, bbrother
bbbb, 2001, nobody
... and so on
and then
count them

Related

How to write SQL statement to select for data broken up for each month of the year?

I am looking for a way to write an SQL statement that selects data for each month of the year, separately.
In the SQL statement below, I am trying to count the number of instances in the TOTAL_PRECIP_IN and TOTAL_SNOWFALL_IN columns when either column is greater than 0. In my data table, I have information for those two columns ("TOTAL_PRECIP_IN" and "TOTAL_SNOWFALL_IN") for each day of the year (365 total entries).
I want to break up my data by each calendar month, but am not sure of the best way to do this. In the statement below, I am using a UNION statement to break up the months of January and February. If I keep using UNION statements for the remaining months of the year, I can get the answer I am looking for. However, using 11 different UNION statements cannot be the optimal solution.
Can anyone give me a suggestion how I can edit my SQL statement to measure from the first day of the month, to the last day of the month for every month of the year?
select monthname(OBSERVATION_DATE) as "Month", sum(case when TOTAL_PRECIP_IN or TOTAL_SNOWFALL_IN > 0 then 1 else 0 end) AS "Days of Rain" from EMP_BASIC
where OBSERVATION_DATE between '2019-01-01' and '2019-01-31'
and CITY = 'Olympia'
group by "Month"
UNION
select monthname(OBSERVATION_DATE) as "Month", sum(case when TOTAL_PRECIP_IN or TOTAL_SNOWFALL_IN > 0 then 1 else 0 end) from EMP_BASIC
where OBSERVATION_DATE between '2019-02-01' and '2019-02-28'
and CITY = 'Olympia'
group by "Month"```
Your table structure is too unclear to tell you the exact query you will need. But a general easy idea is to build the sum of your value and then group by monthname and/or by month. Sice you wrote you only want sum values greater 0, you can just put this condition in the where clause. So your query will be something like this:
SELECT MONTHNAME(yourdate) AS month,
MONTH(yourdate) AS monthnr,
SUM(yourvalue) AS yoursum
FROM yourtable
WHERE yourvalue > 0
GROUP BY MONTHNAME(yourdate), MONTH(yourdate)
ORDER BY MONTH(yourdate);
I created an example here: db<>fiddle
You might need to modify this general construct for your concrete purpose (maybe take care of different years, of NULL values etc.). And note this is an example for a MYSQL DB because you wrote about MONTHNAME() which is in most cases used in MYSQL databases. If you are using another DB type, maybe you need to do some modifications. To make sure that answers match your DB type, tag it in your question, please.

SQL store results table with month name

I have several CSV's stored to query against. Each CSV represents a month of data. I would like to count all the records in each CSV and save that data to a table as a row in the table. For instance, the table that represents May should return something that looks like this with June following. The data starts in Feb 2018 and continues to Feb 2019 so year value would be needed as well.
Month Results
----------------
May 18 1170
June 18 1167
I want to run the same query against all the tables for purposes of efficiency. I also want the query to work with all future updates eg. a March 19 table gets added, and the query will still work.
So far, I have this query.
SELECT COUNT(*)
FROM `months_data.*`
I am querying in Google Big Query using Standard SQL.
It sounds like you just want an aggregation that counts rows for each month:
SELECT
DATE_TRUNC(DATE(timestamp), MONTH) AS Month,
COUNT(*) AS Results
FROM `dataset.*`
GROUP BY month
ORDER BY month
You can use the DATE_FORMAT function if you want to control the formatting.
You seem to need union all:
select 2018 as yyyy, 2 as mm, count(*) as num
from feb2018
union all
select 2018 as yyyy, 3 as mm, count(*)
from mar2018
union all
. . .
Note that you have a poor data model. You should be storing all the data in a single table with a date column.

Order an SQL table by year and ranges of years

I would like to be able to order the results in the following way.
There are two columns, one stores years and the other year ranges, and, sometimes, dates, like this:
2017
2016
2014–2016
1980-ongoing
2013
2000 28-27 March
1970
At the moment, I concatenate them and order by DESC, Getting this (showing the concatenated temporary column):
order by CONCAT(IFNULL(CAST(Year_Pub AS VARCHAR(16)) THEN '' ELSE CAST(Year_Pub AS VARCHAR(16))), IFNULL(Date_Freeform THEN '' ELSE Date_Freeform)) DESC
The result is:
2017
2016
2014-2016
2013
200028-27 March
1980-ongoing
1970
However, what I would like to get is this (imagine that this is a list of activities for a CV or similar):
1980-ongoing
2017
2016
2014-2016
2013
2000
1970
That is if there is a span of years, I would like to have the ongoing engagements to appear first, ordered by the start year, then have spans of years ordered by last year and mixed with single years. Dates only occur when Year_Pub is NULL and will have to be removed before concatenation, I imagine.
The separator is an ndash, so I need to split those strings by that somehow as I see from examples that show how to order by the family names in tables that have first name and family name in one column but this is a more complicated situation and I am not really familiar with SQL.
Also, this operation will be performed on a table that comes with an application so I do not want to insert data or columns into their database in case something gets broken.
Using SQL on an ElevateDB database (SQL 2003 standard (ANSI ISO/IEC 9075:2003), but a generic solution will do, I can look up the syntax).
Thank you for the advice.
This is one way to achieve your result:
SELECT
year_pub,
date_freeform,
COALESCE(CAST(year_pub AS VARCHAR(4)), date_freeform) AS year_list
FROM
table_name
ORDER BY
COALESCE(CAST(year_pub AS VARCHAR(4)),
CASE WHEN RIGHT(date_freeform, 4) = 'oing'
THEN '9999'
ELSE RIGHT(date_freeform, 4)
END
) DESC,
date_freeform DESC;

SQL- HAVING Clause Issue

I'm trying to use the MAX() function as a subquery to filter results of my greater query by the last couple of whole years. I realized this was a little bit more complicated than what I initially thought it would need so I created a much simpler query to test out what I would need to do with the HAVING clause in order to get it to work.
I've checked these two posts but it didn't really help (SQL, HAVING clause explained, SQL: HAVING clause)
I don't think my understanding of the HAVING clause is correct because I'm not sure why it's not working. Would someone be able to help and explain?
Note: [Fiscal Year] is NVARCHAR so I figured converting it to INT might work.
SELECT DISTINCT
D.[FISCAL YEAR]
FROM [Dates] AS D
GROUP BY D.[Fiscal Year]
HAVING CONVERT(INT,D.[Fiscal Year]) >= MAX(CONVERT(INT,D.[FISCAL YEAR])) -2
These are my results:
(No column name)
2015
2014
2013
2012
2016
These are the results I should get:
(No column name)
2015
2014
2016
I think this could be done better in the WHERE clause. This solution isn't optimal, but here's what you can do.
SELECT
DISTINCT D.[FISCAL YEAR]
FROM [Dates] AS D
WHERE CONVERT(INT,d.[Fiscal Year])
>= (SELECT MAX(CONVERT(INT,[Fiscal Year])) -2 from Dates)
The problem you are having is you are grouping by the year, thus the max will always be the same as the year for that group.
Here's one option using window functions:
select distinct fiscalyear
from (
select fiscalyear, max(fiscalyear) over () maxfiscalyear
from dates
) t
where fiscalyear >= maxfiscalyear - 2
I don't see the need to use the convert function here either, but if you need to, you can add it back.
SQL Fiddle Demo

How to get month name out of date field

I'm trying to build a query that gives me a year month field with month names instead of the numbers. The output should be similar to this:
Year/month field | Sum field
Januari 2014 100
Februari 2014 12300
Maart 2014 3234
April 2014 4964
I've searched for the way to get the the month name but I must be doing something wrong because I constantly get the error that datename is not a function or an sql error 1064. This i what i've tried:
SELECT id,
YEAR(report_date) AS YEAR,
MONTH(report_date) AS MONTH,
SELECT DATENAME(MONTH, (MONTH(report_date))) ,
CONVERT(VARCHAR(3), DATENAME(MONTH, report_date)) SUM(num) AS participants_month
FROM participants
WHERE unit_id = 10
GROUP BY unit_id,
MONTH(report_date)
ORDER BY report_date ASC;
Tried to make this question as clear as possible. If something isn't clear tell me and I'll try to explain it. Really hope someone could point me out in the right direction.
In SQL Server you use DATENAME(month, date):
SQL Server Fiddle
But in MySQL you use MONTHNAME(date):
MySQL Fiddle
From the error you are receiving I guess you do not use SQL Server as your database management system, so in MySQL you should use MONTHNAME(date).
From the error, I suppose, you are using MySQL.But the DATENAME() is Transact-SQL function.
In MySQL, you can use
MONTH(yourdate)
instead