SQL using count in case statement - sql

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];

Related

update query with special characters as data in a oracle table

I am trying to update a column QUERY1 on the below table,
ctrl_id query1
C001 NULL
query to be updated in QUERY1 column - SELECT ‘C001’ as CTRL_ID, ‘SRC1’ as SOURCE, [Company Code], Sum([Total AV]) FROM $Src_tbl1 GROUP BY [Company Code]
Below is the query that i use,
update table test1 set QUERY1= ''SELECT ‘C001’ as CTRL_ID, ‘SRC1’ as SOURCE, [Company Code], Sum([Total AV]) FROM $Src_tbl1 GROUP BY [Company Code]'' WHERE CTRL_ID='C001'
This query is failing. Please assist.
You must use 2 single quotes for storing a single quote ':
update
test1
set QUERY1= 'SELECT ''C001'' as CTRL_ID, ''SRC1'' as SOURCE, [Company Code], Sum([Total AV]) FROM $Src_tbl1 GROUP BY [Company Code] WHERE CTRL_ID=''C001''';
This will store the value as:
SELECT 'C001' as CTRL_ID, 'SRC1' as SOURCE, [Company Code], Sum([Total AV]) FROM
$Src_tbl1 GROUP BY [Company Code] WHERE CTRL_ID='C001'
As you can see at the end there are 3 single quotes:
the first 2 are used to escape the closing single quote of 'C001'
and the 3d to end the whole value of QUERY1.
If you want the value stored as:
'SELECT 'C001' as CTRL_ID, 'SRC1' as SOURCE, [Company Code], Sum([Total AV]) FROM $Src_tbl1 GROUP BY [Company Code] WHERE CTRL_ID='C001''
then you must do this:
update
test1
set QUERY1= '''SELECT ''C001'' as CTRL_ID, ''SRC1'' as SOURCE, [Company Code], Sum([Total AV]) FROM $Src_tbl1 GROUP BY [Company Code] WHERE CTRL_ID=''C001''''';
Set query1='select ''coo1'' as ctrl_id, ''src1'' as source,
Company_code,sum (total_avg) from table group by company_code'

Script help - count , total and avg

I have the following script, trying to count how many distinct customers are there , how many distinct orders , what is total of all orders under £15 and its's avg, total of orders above £20 and it's avg.
with consignments as
(select
[Sell-to Customer No_],
[Convert-to Document No_],
ic.[Shipping Agent Service Code],
[Pick Completed DateTime] as [Shipped DateTime],
ROUND((ic.[Amount Including VAT] + ic.Postage + ic.[Gift Wrap Price] +
ic.[Handling Fee] + ic.[Personalisation Fee]),2) as [Document Amount]
from dbo.[Temp$Consignment] ic inner join [dbo].
[Temp$Order] oh
on ic.[Owner Header GuID]=oh.[Order Guid]
where ic.[Shipping Agent Service Code]='secstan' and ic.[Pick Completed
DateTime] >= '2016-11-01T00:00:00.000' AND
ic.[Pick Completed DateTime] <= '2016-11-30T23:59:55.000' ),summary as
(select *,CASE WHEN [Document Amount] > 15 THEN 1 ELSE 0 END as 'Over15'
from consignments )select * from summary
I have working script like below, but as I am new to sql I am bit confused how to convert above script to below.
select amountclass,[Shipping Agent Service Code],
count(distinct [Sell-to Customer No_]) as Total_customers,
count(*) as Total_orders,
sum([Amount]) as total_revenue,
avg([Amount] * 1.0) as AOV
from
(
select [Sell-to Customer No_], oh.[Original Order No_], [Amount],ic.
[Shipping Agent Service Code],
case when [Amount] <= 20 then 'Under_20'
else 'Over_20'
end as amountclass
from [TBW_BI].[dbo].[Temp$Order] oh INNER JOIN [TBW_BI].[dbo].
[Temp$Consignment] IC
ON IC.[Owner Header GuID]=OH.[Order Guid]
where[order date] >= '2016-09-01' AND
[order date] <= '2016-09-30' AND [COUNTRY]='UNITED KINGDOM' and
[document type] like 'ord%' and ic.[Shipping Agent Service
Code]='secstan'
) dt
group by amountclass,[Shipping Agent Service Code]
order by amountclass,[Shipping Agent Service Code]
It looks like you have a query with a 2 Common Table Expressions (CTE) and you want to convert the CTE to a derived table. First, we can eliminate one of the CTEs.
summary as
(select *,CASE WHEN [Document Amount] > 15 THEN 1 ELSE 0 END as 'Over15'
from consignments )
select * from summary
The CTE for summary is unnecessary. We can convert that code to this:
select *,CASE WHEN [Document Amount] > 15 THEN 1 ELSE 0 END as 'Over15'
from consignments
Now, instead of using the consignments CTE; we can copy the sql code within it to create a derived table.
select *,CASE WHEN [Document Amount] > 15 THEN 1 ELSE 0 END as 'Over15'
from (
select [Sell-to Customer No_],
[Convert-to Document No_],
ic.[Shipping Agent Service Code],
[Pick Completed DateTime] as [Shipped DateTime],
ROUND((ic.[Amount Including VAT] + ic.Postage + ic.[Gift Wrap Price] +
ic.[Handling Fee] + ic.[Personalisation Fee]),2) as [Document Amount]
from dbo.[Temp$Consignment] ic
inner join [dbo].[Temp$Order] oh on ic.[Owner Header GuID]=oh.[Order Guid]
where ic.[Shipping Agent Service Code]='secstan'
and ic.[Pick Completed
DateTime] >= '2016-11-01T00:00:00.000'
AND
ic.[Pick Completed DateTime] <= '2016-11-30T23:59:55.000' ) as t

Workaround for PIVOT statement

I have this query, is taking like 2 minutes to resolve, I need to find a workaround, I know that UNPIVOT has a better solution using CROSS APPLY, is there anything similar for PIVOT?
SELECT [RowId], [invoice date], [GL], [Entité], [001], [Loc], [Centre Cout], [Compte_1], [Interco_1], [Futur_1], [Department], [Division], [Compagnie], [Localisation], [Centre/Cout], [Compte], [Interco], [Futur], [Account], [Mobile], [Last Name], [First Name], [license fee], [GST], [HST], [PST], [Foreign Tax], [Sales Tax License], [Net Total], [Total], [ServiceType], [Oracle Cost Center], [CTRL], [EXPENSE], [Province]
FROM
(SELECT fd.[RowId], fc.[ColumnName], fd.[Value]
FROM dbo.FileData fd
INNER JOIN dbo.[FileColumn] fc
ON fc.[FileColumnId] = fd.[FileColumnId]
WHERE FileId = 1
AND TenantId = 1) x
PIVOT
(
MAX(Value)
FOR [ColumnName] IN ( [invoice date], [GL], [Entité], [001], [Loc], [Centre Cout], [Compte_1], [Interco_1], [Futur_1], [Department], [Division], [Compagnie], [Localisation], [Centre/Cout], [Compte], [Interco], [Futur], [Account], [Mobile], [Last Name], [First Name], [license fee], [GST], [HST], [PST], [Foreign Tax], [Sales Tax License], [Net Total], [Total], [ServiceType], [Oracle Cost Center], [CTRL], [EXPENSE], [Province])
) AS p
Pivots are great, but so are Conditional Aggregations. Also, there would be no datatype conficts or conversions necessary
SELECT [RowId]
,[invoice date] = max(case when [FileColumnId] = ??? then Value end)
,[GL] = max(case when [FileColumnId] = ??? then Value end)
,... more fields
FROM dbo.FileData fd
WHERE FileId = 1
AND TenantId = 1
Group By [RowId]
EDIT
You could add back the join to make it more readable.

SQL Sub-query (Where In)

I get an error with my sub-query and am not seeing what I am doing wrong. Sub-query works on it's on. There Where-In is obviously what is the problem. Also tried EXISTS.
select [ID NUMBER], [PERNO], [TITLE], [INITIALS], [SURNAME], [DATE OF BIRTH]
from dbo.[DATASEPT002]
WHERE [ID NUMBER] IN
( SELECT [ID NUMBER], COUNT([PERSALNO]) AS COUNTOF
FROM [dbo].[DATASEPT]
GROUP BY [ID NUMBER] HAVING COUNT([PERSALNO]) >1 )
You have two columns in the subquery. Only one can be used for the IN comparison:
select [ID NUMBER], [PERNO], [TITLE], [INITIALS], [SURNAME], [DATE OF BIRTH]
from dbo.[DATASEPT002] t
WHERE [ID NUMBER] IN (SELECT [ID NUMBER]
FROM [dbo].[DATASEPT]
GROUP BY [ID NUMBER]
HAVING COUNT([PERSALNO]) > 1
);
However, I would expression this more typically using window functions:
select t.*
from (select t.*, count(*) over (partition by persalno) as cnt
from DATASEPT002 t
) t
where cnt > 1;

T-SQL [UNION ALL] removing records from query result

Have a simple UNION ALL query marrying the results of two queries. The first query, run independently, returns 1208 records and the second 14. I would expect a properly syntaxed UNION ALL to return 1222 records but mine falls to 896.
Makes zero sense to me:
SELECT a.WBS_ELEMENT_ID as [WBS Element],
a.WBS_ELEMENT_DESC as [WBS Element Desc],
a.UHC_INDUSTRY as [Industry],
a.UHC_SECTOR as [Sector],
a.UHC_DUNS_NUMBER as [UHC DUNS Number],
a.UHC_DUNS_NAME as [UHC DUNS Name],
a.PRIORITY_SUB_SECTOR as [Priority Sub Sector],
a.BUDGET_ALLOCATION as [Budget Allocation],
a.LAST_UPDATED_ON as [Last Updated]
FROM DimSectorPd a
WHERE a.wbs_element_id is not null
UNION ALL
SELECT ROW_NUMBER() OVER (ORDER BY a.wbs_element_desc) as [WBS Element],
a.WBS_ELEMENT_DESC as [WBS Element name],
a.UHC_INDUSTRY as [Industry],
a.UHC_SECTOR as [Sector],
a.UHC_DUNS_NUMBER as [UHC DUNS Number],
a.UHC_DUNS_NAME as [UHC DUNS Name],
a.PRIORITY_SUB_SECTOR as [Priority Sub Sector],
a.BUDGET_ALLOCATION as [Budget Allocation],
a.LAST_UPDATED_ON as [Last Updated]
from dimsectorpd a where a.WBS_ELEMENT_ID is null
Your queries should return all rows in the table. Unless the table changes between executions, the results from running the subqueries separately should be the same as from running them with the UNION ALL.
As a note, if you want to simplify the query, then you can do:
SELECT COALESCE(a.WBS_ELEMENT_ID,
ROW_NUMBER() OVER (PARTITION BY wbs_element_id ORDER BY a. wbs_element_desc)
) as [WBS Element],
a.WBS_ELEMENT_DESC as [WBS Element Desc],
a.UHC_INDUSTRY as [Industry],
a.UHC_SECTOR as [Sector],
a.UHC_DUNS_NUMBER as [UHC DUNS Number],
a.UHC_DUNS_NAME as [UHC DUNS Name],
a.PRIORITY_SUB_SECTOR as [Priority Sub Sector],
a.BUDGET_ALLOCATION as [Budget Allocation],
a.LAST_UPDATED_ON as [Last Updated]
FROM DimSectorPd a;
Obviously there is nothing wrong with your syntax, but if you want to try a different approach to getting your UNION ALL to work with ROW_NUMBER. Here it is:
;WITH q1
AS (
SELECT a.WBS_ELEMENT_ID AS [WBS Element]
,a.WBS_ELEMENT_DESC AS [WBS Element Desc]
,a.UHC_INDUSTRY AS [Industry]
,a.UHC_SECTOR AS [Sector]
,a.UHC_DUNS_NUMBER AS [UHC DUNS Number]
,a.UHC_DUNS_NAME AS [UHC DUNS Name]
,a.PRIORITY_SUB_SECTOR AS [Priority Sub Sector]
,a.BUDGET_ALLOCATION AS [Budget Allocation]
,a.LAST_UPDATED_ON AS [Last Updated]
FROM DimSectorPd a
WHERE a.wbs_element_id IS NOT NULL
UNION ALL
SELECT b.WBS_ELEMENT_ID AS [WBS Element] --just bring NULL values
,b.WBS_ELEMENT_DESC AS [WBS Element name]
,b.UHC_INDUSTRY AS [Industry]
,b.UHC_SECTOR AS [Sector]
,b.UHC_DUNS_NUMBER AS [UHC DUNS Number]
,b.UHC_DUNS_NAME AS [UHC DUNS Name]
,b.PRIORITY_SUB_SECTOR AS [Priority Sub Sector]
,b.BUDGET_ALLOCATION AS [Budget Allocation]
,b.LAST_UPDATED_ON AS [Last Updated]
FROM dimsectorpd b
WHERE b.WBS_ELEMENT_ID IS NULL
)
SELECT CASE
WHEN q1.[WBS Element] IS NULL
THEN ROW_NUMBER() OVER (ORDER BY q1.WBS_Element_Desc)
ELSE q1.[WBS Element]
END [WBS_Element]
,q1.[WBS Element Desc]
,q1.Industry
,q1.Sector
,q1.[UHC DUNS Number]
,q1.[UHC DUNS Name]
,q1.[Priority Sub Sector]
,q1.[Budget Allocation]
,q1.[Last Updated]
FROM q1
Here is a simplified example can you see if it works on your server?
SELECT a.low AS [My ID],
a.name AS [My Letter]
FROM master..spt_values as a
WHERE low is not null
UNION ALL
SELECT ROW_NUMBER() OVER (ORDER BY a.name) AS [My ID],
a.name AS [My Letter]
FROM master..spt_values as a
WHERE a.low is null
master..spt_values as 2515 rows on my system...