SELECT DISTINCT CASE COUNT - sql

I'm new to SQL, and trying to return a column in a data set that Counts and/or Sums the total of 1 column only when another column meets the criteria
I've got the below in my Select clause, but as I Group the data later in query and don't output the G.[Constituent ID] I cant count that row (and don't want to as it wont group the data the way i want).
Is there a way around this?
(I'm using Microsoft SQL)
SELECT
(Case WHEN G.[Constituent ID] IN ('2014', '2015', '2016', '2017', '2018') THEN COUNT(DISTINCT G.[Gift Import ID])) AS [COUNT of Gifts Anonymous]
This is my whole statement
SELECT
a.Apl_Appeal_ID AS [Appeal ID],
A.Apl_Description AS [Appeal Description],
A.Apl_Start_date AS [Appeal Start Date],
A.Apl_Campaign_ID AS [Campaign ID],
SUM(A.Apl_No_solicited) AS [Number Solicited],
SUM(A.Apl_ApE_1_01_Amount) AS [Appeal Expenses],
RIGHT(A.Apl_Appeal_ID,1) AS [PackCode],
A.Apl_AtrCat_1_01_Description AS [Gift Classification],
A.Apl_AtrCat_2_01_Description AS [Channel],
A.Apl_AtrCat_3_01_Description AS [MD/Corp],
A.Apl_AtrCat_4_01_Description AS [Purpose],
A.Apl_AtrCat_5_01_Description AS [Campaign],
A.Apl_AtrCat_6_01_Description AS [Wave],
A.Apl_AtrCat_7_01_Description AS [Supplier],
A.Apl_AtrCat_8_01_Description AS [Timing],
A.Apl_AtrCat_9_01_Description AS [Year],
COUNT(DISTINCT G.[Constituent ID]) AS [COUNT of Donors],
COUNT(DISTINCT G.[Gift Import ID]) AS [COUNT of Gifts],
SUM(G.[Gift Amount]) AS [Income],
(Case WHEN G.[Constituent ID] IN ('2014', '2015', '2016', '2017', '2018') THEN COUNT(DISTINCT G.[Gift Import ID])) AS [COUNT of Gifts Anonymous]
FROM dbo.[FHF_Appeals] A
LEFT OUTER JOIN dbo.FHF_Gifts_ExcludingRG G
ON A.Apl_Appeal_ID = G.[Appeal List]
WHERE (a.Apl_Campaign_ID = '1002100-Acquisition' AND A.Apl_AtrCat_2_01_Description LIKE 'Direct_Mail')
AND A.Apl_Start_date >= '1/1/2014'
GROUP BY
A.Apl_Appeal_ID,
A.Apl_Description,
A.Apl_Start_date,
A.Apl_Campaign_ID,
A.Apl_AtrCat_1_01_Description,
A.Apl_AtrCat_2_01_Description,
A.Apl_AtrCat_3_01_Description,
A.Apl_AtrCat_4_01_Description,
A.Apl_AtrCat_5_01_Description,
A.Apl_AtrCat_6_01_Description,
A.Apl_AtrCat_7_01_Description,
A.Apl_AtrCat_8_01_Description,
A.Apl_AtrCat_9_01_Description

I think you want the CASE expression as an argument to the COUNT(DISTINCT):
COUNT(DISTINCT CASE WHEN G.[Constituent ID] IN ('2014', '2015', '2016', '2017', '2018')
THEN G.[Gift Import ID]
END) AS [COUNT of Gifts Anonymous]

Related

SQL create column for every week (Loop?)

I need to make a report for weekly changes.
This is the code for todays amount
SELECT
[Entry No_],
[Customer No_],
[Posting Date],
[Description],
[Currency Code],
Trans_type = case when [Deposit]=1 then 'Deposit'
when [Imprest]=1 then 'Imprest'
else 'Other' end,
A.Amount
FROM Table1
LEFT JOIN
(
SELECT Distinct [Cust_ Ledger Entry No_],
SUM ([Amount EUR]) as 'amount'
FROM Table2
group by [Cust_ Ledger Entry No_]
having
SUM ([Amount EUR]) <> '0'
)A
on [Entry No_] = A.[Cust_ Ledger Entry No_]
Where
A.Amount is not NULL
Code to generate data for previous week is here (adding only where clause):
SELECT
[Entry No_],
[Customer No_],
[Posting Date],
[Description],
[Currency Code],
Trans_type = case when [Deposit]=1 then 'Deposit'
when [Imprest]=1 then 'Imprest'
else 'Other' end,
A.Amount
FROM Table1
LEFT JOIN
(
SELECT Distinct [Cust_ Ledger Entry No_],
SUM ([Amount EUR]) as 'amount'
FROM Table2
where [posting Date] < '2020-11-23'
group by [Cust_ Ledger Entry No_]
having
SUM ([Amount EUR]) <> '0'
)A
on [Entry No_] = A.[Cust_ Ledger Entry No_]
Where
A.Amount is not NULL
It would be enough to union both queries and then export to Excel and make pivot, but problem is that I need results of last 50 weeks. Is there any smart way to avoid union 50 tables and run one simple code to generate weekly report?
Thanks
it might be easier with sample, but I don't know how to paste table here..
Maybe it is true, i dont need union here, and group by would be enough, but it stills sounds difficult for me :)
Ok. Lets say table has such headers: Project | Country | date | amount
The code below returns amount for todays date
Select
Project,
SUM(amount)
From Table
Group by Project
I actually need todays date and also the results of previous weeks (What was the result on November 22 (week 47), November 15 (week 46) and so on.. total 50 weeks from todays date).
Code for previous week amount is here:
Select
Project,
SUM(amount)
From Table
Where Date < '2020.11.23'
Group by Project
So my idea was to create create 50 codes and join the results together, but i am sure it is a better way to do this. Besides i dont want to edit this query every week and add a new date for it.
So any ideas, to make my life easier?
if I have understood your requirement correctly, all you need to do is extract the week from the date e.g.
Select
Project,
datepart(week, date),
SUM(amount)
From Table
Where Date < '2020.11.23'
Group by Project, datepart(week, date)

How to select max date over the year function

I am trying to select the max date over the year, but it is not working. Any ideas on what to do?
SELECT a.tkinit [TK ID],
YEAR(a.tkeffdate) [Rate Year],
max(a.tkeffdate) [Max Date],
tkrt03 [Standard Rate]
FROM stageElite.dbo.timerate a
join stageElite.dbo.timekeep b ON b.tkinit = a.tkinit
WHERE a.tkinit = '02672'
and tkeffdate BETWEEN '2014-01-01' and '12-31-2014'
GROUP BY a.tkinit,
tkrt03,
a.tkeffdate
Perhaps you only want it by year and not rolled up by calendar date. For SQL server you can try this.
SELECT
…
MaxDate = MAX(a.tkeffdate) OVER (PARTITION BY a.tkinit, YEAR(a.tkeffdate)))
…
Or you could modify the query above to group by the year instead of date-->
GROUP BY a.tkinit,
tkrt03,
YEAR(a.tkeffdate)
You seem to want only one row and all the columns. Use ORDER BY and TOP:
SELECT TOP (1) tr.tkinit as [TK ID],
YEAR(tr.tkeffdate) as [Rate Year],
a.tkeffdate as [Max Date],
tkrt03 as [Standard Rate]
FROM stageElite.dbo.timerate tr JOIN
stageElite.dbo.timekeep tk
ON tk.tkinit = tr.tkinit
WHERE tr.tkinit = '02672' AND
tr.tkeffdate >= '2014-01-01' AND
tr.tkeffdate < '2015-01-01'
ORDER tr.tkeffdate DESC;
Note that I also fixed your date comparisons and table aliases.

SQL WHERE/HAVING Condition

Currently I'm working in a forecasting project to estimate cash flow. This how the SQL query looks like:
SELECT [Date] AS ds, SUM([Sales Amount]) AS y, [Item ID]
FROM dbo.[Table]
GROUP BY [Date], [Item ID]
ORDER BY ds;
And in order to forecast sales I use an R package that strictly request that there has to be at least 2 instances where the forecast value(Sales) appears.
However there some instances in my query where an item it has been transacted just once.
Could you help me with an HAVING or WHERE condition where excludes all the items that were transacted just once?
Thanks!
I would add a count and use that:
SELECT ds, y, [Item ID]
FROM (SELECT [Date] AS ds, SUM([Sales Amount]) AS y, [Item ID],
COUNT(*) OVER (PARTITION BY [Item ID]) as cnt
FROM dbo.[Table]
GROUP BY [Date], [Item ID]
) t
WHERE cnt >= 2
ORDER BY ds;
You can use an extra filtering condition in a WHERE clause:
SELECT
[Date] AS ds
,SUM([Sales Amount]) AS y
,[Item ID]
FROM dbo.[Table]
WHERE [Item ID] in ( -- filters out the items with less than 2 samples
select distinct [Item ID]
from dbo.[Table]
group by [Item ID], [Date] having count(*) > 1
)
GROUP BY [Date]
,[Item ID]
ORDER BY ds

SQL using count in case statement

I'm trying to group all activity where the count is less than 5 (for data sharing reasons).
The ID Code and ID Name give me high level numbers, but as soon as I include "shop code" I get some low level numbers for customers that go to odd shops once or twice.
Select Count(*) [Activity],
T.[ID Code],
T.[ID Name],
Case when Count(*) < 6 then 'Other Shop' Else T.Shop End [Shop Code]
From MyTable T
Group By T.[ID Code],
T.[ID Name],
Case when Count(*) < 6 then 'Other Shop' Else T.Shop End
But obviously I can't use a count in a case statement. I've tried some of the solutions to similar questions but none of them work!
Thanks
The problem is the GROUP BY:
Select Count(*) as [Activity],
T.[ID Code],
T.[ID Name],
(Case when Count(*) < 6 then 'Other Shop' Else T.Shop
End) as [Shop Code]
From MyTable T
Group By T.[ID Code],
T.[ID Name];
Aggregate functions (or expressions with aggregates) don't belong in the GROUP BY. These are calculated in the SELECT, not used to define groups.
You can use the HAVING and UNION ALL statement, like this:
Select Count(*) as [Activity],
T.[ID Code],
T.[ID Name],
'Other Shop' [Shop Code]
From MyTable T
Group By T.[ID Code],
T.[ID Name]
having Count(*) < 6
union all
Select Count(*) as [Activity],
T.[ID Code],
T.[ID Name],
T.Shop [Shop Code]
From MyTable T
Group By T.[ID Code],
T.[ID Name]
having Count(*) >= 6
select
count(*) as activity,
code,
name,
Case when Count(*) < 6 then 'Other Shop' Else shopcode End as shopcode
from mytable group by code, name ,shopcode
The example below is a test in SQL Server.
It uses a window function for count, to change the Shop code.
And then groups it all, including that modified shopcode.
declare #ShopTable table ([ID Code] varchar(30), [ID Name] varchar(30), Shop varchar(30));
insert into #ShopTable ([ID Code], [ID Name], Shop) values
('S1','Shop 1','AA'),
('S1','Shop 1','BB'),
('S1','Shop 1','BB'),
('S1','Shop 1','CC'),
('S1','Shop 1','CC'),
('S1','Shop 1','CC'),
('S2','Shop 2','XX'),
('S2','Shop 2','YY');
select
count(*) as [Activity],
[ID Code],
[ID Name],
[Shop Code]
from (
select
[ID Code],
[ID Name],
case when count(*) over (partition by [ID Code], [ID Name]) < 6 then 'Other Shop' else Shop end as [Shop Code]
from #ShopTable
) Q
group by [ID Code], [ID Name], [Shop Code];

Find the most recent row of a group

I know there is no "last" row so I hope I'm clear that isn't what I'm really looking for. I want to select the rows in a table if the value of one particular field is the last alphabetically. I'll try my best to draw it out below. I'm a bit of a novice so please bear with me...
TABLE
[Order Number], [Delivery Date], [Order Qty], [Shipped Qty], [Bill To], [Ship To], [Invoice Number]
There are many times when we will reissue invoices and that invoice number will increment by a letter. This will also update additional field values as well. Below is a typical set with multiples invoices...
'987654', '2014-05-01 00:00:00', '100', '90', 'BillToXYZ', 'ShipToXYZ', '987654A' - NEW RECORD -
'987654', '2014-05-01 00:00:00', '-100', '-90', 'BillToXYZ', 'ShipToXYZ', '987654B' - NEW RECORD -
'987654', '2014-05-01 00:00:00', '100', '100', 'BillToXYZ', 'ShipToNEWSHIPTOLOCATION', '987654C' - NEW RECORD -
'987654', '2014-05-01 00:00:00', '10', '10', 'BillToXYZ', '2ndNEWSHIPTOLOCATION', '987654D' - NEW RECORD -
What I need is to query all the above fields and only bring back those where the [Invoice Number] is the last(alphabetically) (in this case 987654D) but also have it SUM the values of the [Order Qty] and [Shipped Qty] for all of the records regardless of [Invoice Number].
If I can provide any additional information please let me know. Thank you in advance.
It possible to use the ROW_NUMBER function to get the last row in a group setting the ORDER BY descending and then using a filter to get the row with the value 1.
The SUM and MAX with windowing help to get the other aggregate values.
WITH D AS (
SELECT [Order Number]
, [Delivery Date]
, SUM([Order Qty]) OVER (PARTITION BY [Order Number]) [Total Order Qty]
, [Total Shipped Qty]
= SUM([Shipped Qty]) OVER (PARTITION BY [Order Number])
, [Bill To]
, [Ship To]
, [Last Invoice Number]
= MAX([Invoice Number]) OVER (PARTITION BY [Order Number])
, ID = ROW_NUMBER() OVER (PARTITION BY [Order Number]
ORDER BY [Invoice Number] DESC)
FROM Table1
)
SELECT [Order Number]
, [Delivery Date]
, [Total Order Qty]
, [Total Shipped Qty]
, [Bill To]
, [Ship To]
, [Last Invoice Number]
FROM D
WHERE ID = 1
SQLFiddle demo
Looks to me like you can use a GROUP BY and aggregates as suggested by other answers, but put that in a subquery so that you can link your 'main' table to it and get the detail values for the latest invoice. Does the following code do what you're looking for?
CREATE TABLE #Table
(
OrderNumber int,
DeliveryDate datetime,
OrderQty int,
ShippedQty int ,
BillTo varchar(10),
ShipTo varchar(100),
InvoiceNumber varchar(20)
)
INSERT INTO #Table
(
OrderNumber,
DeliveryDate,
OrderQty,
ShippedQty,
BillTo,
ShipTo,
InvoiceNumber
)
SELECT '987654', '2014-05-01 00:00:00', '100', '90', 'BillToXYZ', 'ShipToXYZ', '987654A' UNION
SELECT '987654', '2014-05-01 00:00:00', '-100', '-90', 'BillToXYZ', 'ShipToXYZ', '987654B' UNION
SELECT '987654', '2014-05-01 00:00:00', '100', '100', 'BillToXYZ', 'ShipToNEWSHIPTOLOCATION', '987654C' UNION
SELECT '987654', '2014-05-01 00:00:00', '10', '10', 'BillToXYZ', '2ndNEWSHIPTOLOCATION', '987654D'
SELECT t.*, s.TotalOrderQty, s.TotalShippedQty
FROM
#Table t
INNER JOIN
(
SELECT
OrderNumber,
MAX(InvoiceNumber) LastInvoice,
SUM(OrderQty) TotalOrderQty,
SUM(ShippedQty) TotalShippedQty
FROM #Table
GROUP BY OrderNumber
) s ON
t.OrderNumber = s.OrderNumber AND
t.InvoiceNumber = s.LastInvoice
DROP TABLE #Table
Is this what you're going after?
EDIT 2: Got clarification from OP. Have edited my solution to bring up aggregation for complete order but only the line item information of the latest invoice. Fiddle here: http://sqlfiddle.com/#!3/08bb0/6
SELECT t1.[Order Number],
t2.[Max Invoice Number],
t1.[Ship To],
t2.[Sum Order Qty],
t2.[Sum Shipped Qty]
FROM Table1 t1 INNER JOIN
(SELECT [Order Number],
MAX([Invoice Number] ) AS [Max Invoice Number],
SUM([Order Qty]) AS [Sum Order Qty],
SUM([Shipped Qty]) AS [Sum Shipped Qty]
FROM Table1
GROUP BY [Order Number]) t2
ON t1.[Invoice Number] = t2.[Max Invoice Number]
ORDER BY t1.[Order Number];
You can add more columns from the D invoice by placing them in the SELECT list from t1, as I did with [Ship To].
EDIT 1: Added grouping so whole table is considered. To be fair, Martin K. posted this answer first.