SQL Sub-query (Where In) - sql

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;

Related

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

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.

Turning results in comma separated list

I'm using this code to get the following results:
Select [Doc #],
[Production Number]
From vwLiveDocuments
Where [production number] IN
(
SELECT [production number]
FROM vwLiveDocuments
where [tags] LIKE N'%name of tag%'
Group by [production number]
Having Count (*) > 1
)
I'll get the following results:
'Doc #' 'Production number'
117611 CGI00069441
47864 CGI00069441
47865 CGI00069457
117901 CGI00069457
47866 CGI00069460
117904 CGI00069460
121479 CGI00071490
53934 CGI00071490
You can see duplicate results in Production number. what i would like is to convert this list to get the following results:
'Production number' 'Doc #'
CGI00069441 117611,47864
CGI00069457 47865,117901
CGI00069460 47866,117904
CGI00071490 121479,53934
Where for every duplicate "Prod number" i would like to get a comma seperate list of the doc # that are duplicates.
Use For xml path() trick to do this.
;WITH cte
AS (SELECT [Doc #],
[Production Number]
FROM vwLiveDocuments
WHERE [production number] IN (SELECT [production number]
FROM vwLiveDocuments
WHERE [tags] LIKE N'%20150126-Appendix B%'
GROUP BY [production number]
HAVING Count (*) > 1))
SELECT [Production number],
Stuff((SELECT ',' + CONVERT(VARCHAR(10), [doc #])
FROM cte b
WHERE b.[Production number] = a.[Production number]
FOR xml path('')), 1, 1, '') [Doc #]
FROM cte a
GROUP BY [Production number]
ORDER BY [Production Number] ASC

Column invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause

We have a table which will capture the swipe record of each employee. I am trying to write a query to fetch the list of distinct employee record by the first swipe for today.
We are saving the swipe date info in datetime column. Here is my query its throwing exception.
select distinct
[employee number], [Employee First Name]
,[Employee Last Name]
,min([DateTime])
,[Card Number]
,[Reader Name]
,[Status]
,[Location]
from
[Interface].[dbo].[VwEmpSwipeDetail]
group by
[employee number]
where
[datetime] = CURDATE();
Getting error:
Column 'Interface.dbo.VwEmpSwipeDetail.Employee First Name' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Any help please?
Thanks in advance.
The error says it all:
...Employee First Name' is invalid in the select list because it is not contained
in either an aggregate function or the GROUP BY clause
Saying that, there are other columns that need attention too.
Either reduce the columns returned to only those needed or include the columns in your GROUP BY clause or add aggregate functions (MIN/MAX). Also, your WHERE clause should be placed before the GROUP BY.
Try:
select distinct [employee number]
,[Employee First Name]
,[Employee Last Name]
,min([DateTime])
,[Card Number]
,min([Reader Name])
from [Interface].[dbo].[VwEmpSwipeDetail]
where CAST([datetime] AS DATE)=CAST(GETDATE() AS DATE)
group by [employee number], [Employee First Name], [Employee Last Name], [Card Number]
I've removed status and location as this is likely to return non-distinct values. In order to return this data, you may need a subquery (or CTE) that first gets the unique IDs of the SwipeDetails table, and from this list you can join on to the other data, something like:
SELECT [employee number],[Employee First Name],[Employee Last Name].. -- other columns
FROM [YOUR_TABLE]
WHERE SwipeDetailID IN (SELECT MIN(SwipeDetailsId) as SwipeId
FROM SwipeDetailTable
WHERE CAST([datetime] AS DATE)=CAST(GETDATE() AS DATE)
GROUP BY [employee number])
Please Try Below Query :
select distinct [employee number],[Employee First Name]
,[Employee Last Name]
,min([DateTime])
,[Card Number]
,[Reader Name]
,[Status]
,[Location] from [Interface].[dbo].[VwEmpSwipeDetail] group by [employee number],[Employee First Name]
,[Employee Last Name]
,[Card Number]
,[Reader Name]
,[Status]
,[Location] having [datetime]=GetDate();
First find the first timestamp for each employee on the given day (CURDATE), then join back to the main table to get all the details:
WITH x AS (
SELECT [employee number], MIN([datetime] AS minDate
FROM [Interface].[dbo].[VwEmpSwipeDetail]
WHERE CAST([datetime] AS DATE) = CURDATE()
GROUP BY [employee number]
)
select [employee number]
,[Employee First Name]
,[Employee Last Name]
,[DateTime]
,[Card Number]
,[Reader Name]
,[Status]
,[Location]
from [Interface].[dbo].[VwEmpSwipeDetail] y
JOIN x ON (x.[employee number] = y.[employee number] AND x.[minDate] =Y.[datetime]
This should not be marked as mysql as this would not happen in mysql.
sql-server does not know which of the grouped [Employee First Name] values to return so you need to add an aggregate (even if you only actually expect one result). min/max will both work in that case. The same would apply to all the other rows where they are not in the GROUP BY or have an aggregate function (EG min) around them.