Related
I am running this query and I get correct result
SELECT
CONCAT("year", ' - ', TRIM('20' FROM "year") + 1) as 'Years',
SUM("svalue") as 'Value',
'Sale' as 'Type',
"year" as 'Year',
"code" as 'FACode',
FROM "FCJOIN"
WHERE "code" IN
(
SELECT "fccode"
FROM "fcdetails"
)
AND "month" between '04' and '12'
AND "year" IN ( '2016' , '2017' , '2018' , '2019' )
GROUP BY "code", "year"
what i need is , if I add a new column formonth it will gives an error Improper usage of GROUP BY clause ? Please ensure that all non-aggregate columns used in the SELECT clause are also used in GROUP BY clause.
that's my modified query is like this
SELECT
CONCAT("year", ' - ', TRIM('20' FROM "year") + 1) as 'Years',
SUM("svalue") as 'Value',
'Sale' as 'Type',
"year" as 'Year',
"code" as 'FACode',
**"formonth" as 'Period'**
FROM "FCJOIN"
WHERE "code" IN
(
SELECT "fccode"
FROM "fcdetails"
)
AND "month" between '04' and '12'
AND "year" IN ( '2016' , '2017' , '2018' , '2019' )
GROUP BY "code", "year"
is there any way to make this correct group by or or there any way to rewrite ? I dont want the newly added column in group by clause. i am trying this in zoho reports. Any help ?
if you want to show the months of each year for which the code was applicable, then you could aggregate their descriptions/strings with string_agg(). For multiple levels of aggregation i.e sum(svalue) group by (code, year) or group by (year, month description/period) GROUPING SETS could be used.
declare #fcdetails table (fccode int)
insert into #fcdetails(fccode) values(1), (2), (3);
declare #fcjoin table
(
[year] char(4),
[month] tinyint,
svalue int,
code int
) ;
insert into #fcjoin([year], [month], svalue, code)
values
('2016', 5, 10, 1), ('2016', 6, 10, 1), ('2016', 7, 10, 1),
('2017', 5, 4, 2), ('2017', 6, 4, 2),
('2018', 7, 10, 3);
declare #othertable table
(
[themonth] tinyint,
period varchar(20)
);
insert into #othertable([themonth], period)
select distinct [month], {fn MONTHNAME(datefromparts('2020', [month], 1))}
from #fcjoin;
SELECT
CONCAT("year", ' - ', TRIM('20' FROM "year") + 1),
SUM("svalue") as 'Value',
'Sale' as 'Type',
"year" as 'Year',
"code" as 'FACode',
string_agg(o.period, ',') as forperiod
FROM #FCJOIN as f
join #othertable as o on f.month = o.themonth --careful with joins & aggregations
WHERE "code" IN
(
SELECT "fccode"
FROM #fcdetails
)
AND "month" between '04' and '12'
AND "year" IN ( '2016' , '2017' , '2018' , '2019' )
GROUP BY "code", "year";
SELECT
CONCAT("year", ' - ', TRIM('20' FROM "year") + 1),
SUM("svalue") as 'Value',
'Sale' as 'Type',
"year" as 'Year',
"code" as 'FACode',
(select string_agg(o.period, ',')
from #othertable as o
where o.themonth in
(select b.month from #FCJOIN as b where b.year = f.year and b.code = f.code)
) as forperiod
FROM #FCJOIN as f
WHERE "code" IN
(
SELECT "fccode"
FROM #fcdetails
)
AND "month" between '04' and '12'
AND "year" IN ( '2016' , '2017' , '2018' , '2019' )
GROUP BY "code", "year";
SELECT
CONCAT("year", ' - ', TRIM('20' FROM "year") + 1),
SUM("svalue") as 'Value',
'Sale' as 'Type',
"year" as 'Year',
"code" as 'FACode',
o.period as forperiod
FROM #FCJOIN as f
join #othertable as o on f.month = o.themonth --careful with joins & aggregations
WHERE "code" IN
(
SELECT "fccode"
FROM #fcdetails
)
AND "month" between '04' and '12'
AND "year" IN ( '2016' , '2017' , '2018' , '2019' )
GROUP BY GROUPING SETS(("code", "year"),("year", o.period) /*,(code, o.period)*/);
I want to group my data by Date and then find max "Value" for different "Codes". How can I do this - I would like to supply a condition to MAX() but I don't think that is possible.
Columns:
Date: date
Time: time
Value: float
Code: varchar
SELECT MAX([Value] where [Code]='GOLD') AS BestGold,
MAX([Value] where [Code]='SILVER') AS BestSilver
FROM [MyTable]
GROUP BY [Date]
Use a CASE expression:
SELECT
MAX(CASE WHEN [Code]='GOLD' THEN ['Value'] END) AS BestGold,
MAX(CASE WHEN [Code]='SILVER' THEN ['Value'] END) AS BestSilver
FROM [MyTable]
GROUP BY [Date];
The idea here is that the MAX function will only consider values of records for each respective type of code.
You can use inline iif:
SELECT MAX(IIF([Code]='GOLD', [Value], null)) AS BestGold,
MAX(IIF([Code]='SILVER', [Value], null)) as BestSilver
FROM [MyTable]
GROUP BY [Date]
or case:
SELECT MAX(case [Code] when 'GOLD' then [Value] end) AS BestGold,
MAX(case [Code] when 'SILVER' then [Value] end) as BestSilver
FROM [MyTable]
GROUP BY [Date]
Instead, use this
SELECT
[Date],
[Code],
MAX([Value]) AS Best
FROM [MyTable]
where cODE IN ('GOLD','SILVER')
GROUP BY [Date]
If you want it as Separate Column, Then try Pivoting the same
;WITH CTE
AS
(
SELECT
[Date],
[Code],
MAX([Value]) AS Best
FROM [MyTable]
where cODE IN ('GOLD','SILVER')
GROUP BY [Date]
)
SELECT
[Date],
BestGold = [GOLD],
BestSilver = [Silver]
FROM CTE
PIVOT
(
MAX(Best)
FOR
Code IN
(
[GOLD],[SILVER]
)
)P
You could use case;
SELECT
MAX(CASE WHEN Code='GOLD' THEN [VALUE] ELSE -1 END) AS BestGold,
MAX(CASE WHEN Code='SILVER' THEN [VALUE] ELSE -1 END) AS BestSilver
FROM [MyTable]
GROUP BY [Date];
I believe you require something like the below :-
DECLARE #TestCodes Table
(
Date date,
Time time,
Value float,
Code varchar(10)
)
INSERT INTO #TestCodes
VALUES
('2017-08-09','12:00',19900,'Gold'),
('2017-08-09','12:00',15001,'Gold'),
('2017-08-09','12:00',2500,'Gold'),
('2017-08-09','12:00',1200.01,'Metal'),
('2017-08-09','12:00',1900,'Metal'),
('2017-08-09','12:00',1800.1,'Silver'),
('2017-08-09','12:00',1100.01,'Silver'),
('2017-08-09','12:00',100.11,'Silver')
SELECT Date,Code,Max(value) AS MAXPriceOnAnyDate
FROM #TestCodes
GROUP BY [Date],CODE
SELECT * FROM [dbo].[_5200_Sanoma]
WHERE right(left([VARIABLE1)],4),2) = 'RI'
and (
([Year] = '2014' and [Period] in('10','11','12'))
or [Year] = '2015')
or (
[Year] = '2016'
and [Period] in('01','02','03','04','05','06','07','08')--,'09','10','11','12')
)
and ([VARIABLE2] IN(
'String1',
'String2',
'String3',
'String4',
'String5',
'String6',
))
I had to change a few things to be more general but for some reason the first where clause, the right(left([VARIABLE1)],4),2) = 'RI' isn't working because I'm getting back results where that is other two character strings.
This query has worked before I added the last where clause condition
and ([VARIABLE2] IN(
'String1',
'String2',
'String3',
'String4',
'String5',
'String6',
))
So now that I added that it's not working. Any ideas?
Try to split your statements in different lines; you probably meant to do this:
SELECT * FROM [dbo].[_5200_Sanoma]
WHERE right(left([VARIABLE1)],4),2) = 'RI' AND
(
([Year] = '2014' and [Period] in('10','11','12')) OR
([Year] = '2015') OR
([Year] = '2016' and [Period] in('01','02','03','04','05','06','07','08'))
)
and ([VARIABLE2] IN ('String1','String2','String3','String4','String5','String6'))
Guess you just have some parenthesis problems with your or clauses (One of them is not included in the AND part after WHERE right(left([VARIABLE1)],4),2) = 'RI'
Try
and (
([Year] = '2014' and [Period] in('10','11','12')) or
[Year] = '2015' or
([Year] = '2016' and [Period] in('01','02','03','04','05','06','07','08')--,'09','10','11','12')
)
I am trying to get the remaining number of working units for each month, of a sum between a bought number of working unit, and a consumed number of working unit.
I tried two possibilities, but both have flaws :
In the first test, I created a "Months" table that contains every month and every year, in order to show all months in the final matrix I wish to create with these data. With this one, I get the closing whenever there is a consumed working unit, but when there is not, the column is "empty", because it does not get the last closing.
USE OTRS_Revised
SELECT [Customer], CASE WHEN [Year] < 2016 THEN 1 ELSE [Year] END AS [Year], CASE WHEN [Year] < 2016 THEN 0 ELSE [Month] END AS [Month], [Closing] AS Total, SUM([Closing])
OVER (PARTITION BY [Customer] ORDER BY [Year], [Month] ROWS UNBOUNDED PRECEDING) AS Closing
FROM [dbo].[WU_Closing_View]
WHERE [Customer] IN ('CustomerList')
GROUP BY [Customer], [Year], [Month], [Closing]
UNION ALL
SELECT '' AS Customer, CASE WHEN [Year] < 2016 THEN 1 ELSE [Year] END AS [Year], CASE WHEN [Year] < 2016 THEN 0 ELSE [Month] END AS [Month], '' AS Total, '' AS Sum_bought
FROM [dbo].Months
WHERE [Year] <= 2016
GROUP BY Year, Month
ORDER BY Customer, Year, Month
I also tried to do it "month by month", with the below query. It works for one month, but I can't find any way to use this to get the results for each month of the year 2016.
SELECT
(SELECT SUM(Closing) AS Expr1
FROM OTRS_Revised.dbo.WU_Bought_View
WHERE (Customer LIKE 'SomeCustomer') AND (DATEADD(Year, Year - 1900, DATEADD(Month, Month - 1, DATEADD(day, 0, 0))) <= DATEADD(Year, 2016 - 1900, DATEADD(Month, 5 - 1, DATEADD(day, 0, 0))))
GROUP BY Customer)
+
(SELECT SUM(Closing) AS Expr1
FROM OTRS_Revised.dbo.WU_Consumed_View
WHERE (Customer LIKE 'SomeCustomer') AND (DATEADD(Year, Year - 1900, DATEADD(Month, Month - 1, DATEADD(day, 0, 0))) <= DATEADD(Year, 2016 - 1900, DATEADD(Month, 5 - 1, DATEADD(day, 0, 0))))
GROUP BY Customer) AS Expr1,
[Month]
FROM OTRS_Revised.dbo.Months
GROUP BY [Month]
SELECT b.*
FROM
( SELECT CASE WHEN [Year] < 2016 THEN 1 ELSE [Year] END AS [Year], CASE WHEN [Year] < 2016 THEN 0 ELSE [Month] END AS [Month]
FROM [dbo].Months
WHERE [Year] <= 2016
GROUP BY Year, Month
ORDER BY Customer, Year, Month ) AS a
LEFT OUTER JOIN
(SELECT [Customer], CASE WHEN [Year] < 2016 THEN 1 ELSE [Year] END AS [Year], CASE WHEN [Year] < 2016 THEN 0 ELSE [Month] END AS [Month], [Closing] AS Total, SUM([Closing])
OVER (PARTITION BY [Customer] ORDER BY [Year], [Month] ROWS UNBOUNDED PRECEDING) AS Closing
FROM [dbo].[WU_Closing_View]
WHERE [Customer] IN ('CustomerList')
GROUP BY [Customer], [Year], [Month], [Closing]) AS b
ON a.Month = b.Month )
In your approach when you do union the rows that don't have matching months is getting removed. Since you want the months that does not have closing match as well, you need to use the left outer join
Something like this perhaps
DECLARE #T TABLE (ID INT, ProductID INT, TrDate DATE,InOut VARCHAR(10),Amount INT)
INSERT INTO #T VALUES
(1 ,1, '2016-01-01', 'I', 100),
(2 ,2, '2016-01-01', 'I', 100),
(3 ,3, '2016-02-01', 'I', 100),
(4 ,4, '2016-03-01', 'I', 100),
(5 ,1, '2016-03-01', 'I', 100),
(6 ,2, '2016-04-01', 'O', 10),
(7 ,3, '2016-05-01', 'I', 100),
(8 ,5, '2016-05-01', 'I', 100),
(9 ,5, '2016-05-01', 'O', 100),
(10 ,6, '2016-05-01', 'I', 100)
declare #m table (id int, menddate date)
insert #m values
(1,'2015-12-31'),(2,'2016-01-31'),(3,'2016-02-29'),(4,'2016-03-31'),
(5,'2016-04-30'),(6,'2016-05-31'),(7,'2016-06-30'),(4,'2016-07-31')
Select *
from
(
select -- t.*
x.xproductid , x.xyyyymm,
SUM(t.total) OVER (partition by x.xproductid
ORDER BY x.xyyyymm
ROWS UNBOUNDED PRECEDING) AS CumulativeTotal
from
(
SELECT t.ProductID tproductid, year(t.trdate) * 100 + month(t.trdate) tyyyymm,
sum(case when t.Inout = 'I' then t.Amount else t.amount * -1 end) as total
FROM #T t
group by ProductID, year(t.trdate) * 100 + month(t.trdate)
) t
right outer join
(select distinct productid as xproductid,year(m.menddate) * 100 + month(m.menddate) xyyyymm from #t t, #m m) x on x.xproductid = t.tproductid and x.xyyyymm = t.tyyyymm
) z
where z.xyyyymm >= 201601
order by z.xProductID,z.xyyyymm
Note the use of a right outer join to get all the month ends for all products
How can I construct native date data type values in SQL (T-SQL)?
I've added some examples, but please provide your own. My examples assume that the month and year are being stored (or are readily available) as integer values, but maybe your example will assume that the day and the month (or whatever) are stored as text. I can't see the future; surprise me.
SELECT DATEFROMPARTS(#Year, #Month, #Day)
(From SQL Server 2012)
Why, with input data as strings one of the most obvious (and therefore hardly surprising, sorry) solutions would be:
SELECT
mydate = CAST([year] + RIGHT('0' + [month], 2) + '01' AS datetime)
/* or 'AS date' in SQL Server 2008+ */
FROM (
SELECT [month] = '2', [year] = '2011' UNION ALL
SELECT [month] = '03', [year] = '2011' UNION ALL
SELECT [month] = '5', [year] = '2011' UNION ALL
SELECT [month] = '12', [year] = '2011' UNION ALL
SELECT [month] = '8', [year] = '2084' UNION ALL
SELECT [month] = '1', [year] = '1940'
) x;
The following code shows how to create date values from year and month (integer) values:
SELECT DATEADD(
month,
DATEDIFF( month, 0, GETDATE() )
+ x.[month]
- MONTH( GETDATE() ),
DATEADD(
year,
DATEDIFF( year, 0, GETDATE() )
+ x.[year]
- YEAR( GETDATE() ),
0 ) )
FROM ( SELECT [month] = 2, [year] = 2011
UNION ALL
SELECT [month] = 3, [year] = 2011
) x;
Date values from year, month, AND day (integer) values, though maybe the inputs should be sanitized first:
SELECT DATEADD(
day,
x.[day] - DAY(0),
DATEADD(
month,
x.[month] - MONTH(0),
DATEADD(
year,
x.[year] - YEAR(0),
0 ) ) )
FROM ( SELECT [month] = 2, [year] = 2011, [day] = 14
UNION ALL
SELECT [month] = 3, [year] = 2011, [day] = 2
UNION ALL
SELECT [month] = 5, [year] = 2011, [day] = 1
UNION ALL
SELECT [month] = 7, [year] = 2011, [day] = 0
UNION ALL
SELECT [month] = 8, [year] = 2084, [day] = 40
UNION ALL
SELECT [month] = 1, [year] = 1940, [day] = -6
) x;
More example code to create date values from year and month (integer) values, but even simpler than some other example code:
SELECT DATEADD(
month,
x.[month] - MONTH(0),
DATEADD(
year,
x.[year] - YEAR(0),
0 ) )
FROM ( SELECT [month] = 2, [year] = 2011
UNION ALL
SELECT [month] = 3, [year] = 2011
UNION ALL
SELECT [month] = 5, [year] = 2011
UNION ALL
SELECT [month] = 7, [year] = 2011
UNION ALL
SELECT [month] = 8, [year] = 2084
UNION ALL
SELECT [month] = 1, [year] = 1940
) x;