Get results with MAX([Action Date]) per Cases - sql

I would like to get your help in the following case:
I have three columns [Case], [Action Date], [Person ID] and I would like to get the maximum [Action Date] for each Case with the related [Person ID]
As you can see the results for the Case are identical and we have the [Action Date] and [Person ID] which are not, I would like to get back the MAX([Action Date]) (17-04-2020) and the related [Person ID].
select
[Case],
MAX([Action Date]) as 'Last Parking Date',
[Person ID]
from SOURCE_TABLE
group by
[Case],
MAX([Action Date]) as 'Last Parking Date',
[Person ID]
I tried to write it with subselects, but the code became totally confusing.
Thank you so much for you help!

Use ROW_NUMBER() window function:
SELECT [Case], [Person ID], [Action Date] AS [Last Parking Date]
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY [Case] ORDER BY [Action Date] DESC) rn
FROM SOURCE_TABLE
) t
WHERE rn = 1

Related

Recursive CTE increases time

I just made this code, the My_View table has about 9,000 rows, the CTE one has about 14,000. And CTE's first iteration lasted about 0,5s (Handwritting the code), but with the recursion, it lasts about 5 min. The main problem should be at the recursive code, but it shouldn't.
The objective of the code is: Having the following data:
{ID} [Primary ID] [Secondary ID]
Where all the Primary ID's begin with C... And the Secondary ID's with K... The problem is that some Secondary ID's are a link to a Primary ID as following:
{ID} [C010] [K011]
{ID} [C020] [C010]
{ID} [C020] [K020]
So what I want is it to finish like:
{ID} [C010] [K011]
{ID} [C020] [K011]
{ID} [C020] [K020]
{ID} = {[Cod_ 1], [First year], [First month]}
WITH CTE AS ( SELECT DISTINCT [Cod_ 1], [First year], [First month], [Primary ID], [Secondary ID] FROM My_View WHERE [Secondary ID] LIKE 'K%'
UNION ALL
SELECT m1.[Cod_ 1], m1.[First year], m1.[First month], m1.[Primary ID], [m2.Secondary ID] FROM My_View m1 INNER JOIN CTE m2 ON m1.[Cod_ 1] = m2.[Cod_ 1] AND m1.[First year] = m2.[First year] AND m1.[First month] = m2.[First month] AND m1.[Secondary ID] = m2.[Primary ID]
)
SELECT DISTINCT *
FROM CTE
ORDER BY [Cod_ 1], [Primary ID], [Secondary ID]
I believe you need to add WHERE condition like
WHERE m1.[Primary ID] NOT LIKE 'K%'
to avoid recursion-depth error or any similar case may slow it.
So this may help you:
WITH CTE
AS (
SELECT DISTINCT [Cod_ 1]
,[First year]
,[First month]
,[Primary ID]
,[Secondary ID]
FROM My_View
WHERE [Secondary ID] LIKE 'K%'
UNION ALL
SELECT m1.[Cod_ 1]
,m1.[First year]
,m1.[First month]
,m1.[Primary ID]
,[m2.Secondary ID]
FROM My_View m1
INNER JOIN CTE m2 ON m1.[Cod_ 1] = m2.[Cod_ 1]
AND m1.[First year] = m2.[First year]
AND m1.[First month] = m2.[First month]
AND m1.[Secondary ID] = m2.[Primary ID]
WHERE m1.[Primary ID] NOT LIKE 'K%'
)
SELECT DISTINCT *
FROM CTE
ORDER BY [Cod_ 1]
,[Primary ID]
,[Secondary ID]

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

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.

only return records count() = 1

I have this table called myTable
Posting Date|Item No_|Entry Type|
2015-01-13|1234|1
2015-01-13|1234|1
2015-01-12|1234|1
2015-01-12|5678|1
2015-02-12|4567|1
What I want, is only return result where a [Item No_] is ind the table 1 time.
So in this example of my table, i only want to return [Item No_] 5678 and 4567, because there only are one record in it. And then ignore [Item No_] 1234
This is my SQL i have tried, but something is wrong. Can anyone help me?
SELECT [Item No_], [Posting Date], COUNT([Item No_]) AS Antal
FROM myTable
GROUP BY [Entry Type], [Posting Date], [Item No_]
HAVING ([Entry Type] = 1) AND (COUNT([Item No_]) = 1)
ORDER BY [Posting Date] DESC
select [Item No_]
from myTable
group by [Item No_]
having count(*)=1
Remove Posting Date from group by
SELECT [Item No_],Entry Type, COUNT([Item No_]) AS Antal
FROM myTable
GROUP BY [Entry Type], [Item No_]
HAVING COUNT([Item No_]) = 1
or if you want other details use a subquery
SELECT [Item No_],
Entry Type,
Posting Date
FROM myTable a
WHERE EXISTS (SELECT 1
FROM myTable b
where a.[Item No_]=b.[Item No_]
GROUP BY [Entry Type],
[Item No_]
HAVING Count(1) = 1)
ORDER BY [Posting Date] DESC
or window function
;WITH cte
AS (SELECT [Item No_],
[Posting Date],
[Entry Type],
Row_number()OVER (Partition BY [Entry Type], [Item No_] ORDER BY [Item No_]) RN
FROM myTable)
SELECT *
FROM cte a
WHERE NOT EXISTS (SELECT 1
FROM cte b
WHERE a.[Item No_] = b.[Item No_]
AND rn > 1)
ORDER BY [Posting Date] DESC
You can use ROW_Number() in Sql Server
select * from (
SELECT [Item No_], [Posting Date],
Row_Number() over (Parition by [Item No_]
order by [Item No]) RN
FROM myTable
)D
where D.RN=1

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.