CASE returns more than one value - sql

I have this query
select a.Tag,a.Type, a.[Starting Date], a.[Time From 1], a.[Time To 1],
DATEPART(dw,CBCal.Date) as [TagderWoche], CBCal.Date, CBCal.[Customer No_],
Description, [POS Holiday]
from [ReplicationLayer].[BackPro].[CustomerBPCal] as CBCal
CROSS APPLY
(
select Type,[Starting Date],[Time From 1],[Time To 1] ,
(case
WHEN DATEPART(dw,CBCal.Date)=1 then (select [Time From 1] from MyTable
where [Valid at Monday]=1
and [Customer No_]=CBCal.[Customer No_] )
WHEN DATEPART(dw,CBCal.Date)=3 then (select [Time From 1] from MyTable
where [Valid at Wednesday]=1
and [Customer No_]=CBCal.[Customer No_])
WHEN DATEPART(dw,CBCal.Date)=4 then (select [Time From 1] from MyTable
where [Valid at Thursday]=1
and [Customer No_]=CBCal.[Customer No_])
WHEN DATEPART(dw,CBCal.Date)=5 then (select [Time From 1] from MyTable
where [Valid at Friday]=1
and [Customer No_]=CBCal.[Customer No_])
WHEN DATEPART(dw,CBCal.Date)=6 then (select [Time From 1] from MyTable
where [Valid at Saturday]=1
and [Customer No_]=CBCal.[Customer No_])
WHEN DATEPART(dw,CBCal.Date)=7 then (select [Time From 1] from MyTable
where [Valid at Sunday]=1
and [Customer No_]=CBCal.[Customer No_])
end) as Tag
from [CustomerShopAndArrivalTime]
) as a
where CBCal.[Customer No_]=1 and CBCal.[POS Holiday]=0 and Date='2015-04-15'
If I run this query I am getting this error:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, = or when the subquery is used as an expression.
what should I do to solve this problem

You can use function max, min or top like this
select a.Tag,
a.Type,
a.[Starting Date],
a.[Time From 1],
a.[Time To 1],
DATEPART(dw,CBCal.Date) as [TagderWoche],
CBCal.Date,
CBCal.[Customer No_],
Description,[POS Holiday]
from [ReplicationLayer].[BackPro].[CustomerBPCal] as CBCal
CROSS APPLY
(
select Type,[Starting Date],[Time From 1],[Time To 1] ,
(case
WHEN DATEPART(dw,CBCal.Date)=1 then
(select top 1 [Time From 1] from MyTable where [Valid at Monday]=1 and [Customer No_]=CBCal.[Customer No_] )
WHEN DATEPART(dw,CBCal.Date)=3 then
(select top 1 [Time From 1] from MyTable where [Valid at Wednesday]=1 and [Customer No_]=CBCal.[Customer No_])
WHEN DATEPART(dw,CBCal.Date)=4 then
(select top 1 [Time From 1] from MyTable where [Valid at Thursday]=1 and [Customer No_]=CBCal.[Customer No_])
WHEN DATEPART(dw,CBCal.Date)=5 then
(select top 1 [Time From 1] from MyTable where [Valid at Friday]=1 and [Customer No_]=CBCal.[Customer No_])
WHEN DATEPART(dw,CBCal.Date)=6 then
(select top 1 [Time From 1] from MyTable where [Valid at Saturday]=1 and [Customer No_]=CBCal.[Customer No_])
WHEN DATEPART(dw,CBCal.Date)=7 then
(select top 1 [Time From 1] from MyTable where [Valid at Sunday]=1 and [Customer No_]=CBCal.[Customer No_])
end) as Tag
from [CustomerShopAndArrivalTime]
) as a
where CBCal.[Customer No_]=1 and CBCal.[POS Holiday]=0 and Date='2015-04-15'

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

SQL query with multiple time based criteria

I have a database for managing blood lead levels where we have various reporting/exclusion requirements.
For mandatory removal of someone from my area they need a test over 34, and before they are allowed to return they require 3 consecutive tests to be under 27. I have been using the query below to find people that should be removed this looks at their last 3 tests for any over 34, This works to say a person must be excluded based on their last 3 tests, but does not work to generate a complete list of people that should currently be excluded
SELECT x1.[Employee ID]
FROM [Lead Results] AS x1 INNER JOIN Employees ON x1.[Employee ID] = Employees.[Employee ID]
WHERE (((x1.[Test Result])>34) AND (((select count(*)
from [Lead Results] x2
where x2.[Employee ID] = x1.[Employee ID]
and x2.[Date of Test] >= x1.[Date of Test]
))<=3))
GROUP BY x1.[Employee ID]
HAVING ((Count(x1.[Date of Test]))>=1);
I have also made a query to find people that have their last 3 tests under 27, This works fine to say someone can now be returned,
SELECT x1.[Employee ID]
FROM [Lead Results] AS x1 INNER JOIN Employees ON x1.[Employee ID] = Employees.[Employee ID]
WHERE (((x1.[Test Result])<27) AND (((select count(*)
from [Lead Results] x2
where x2.[Employee ID] = x1.[Employee ID]
and x2.[Date of Test] >= x1.[Date of Test]
))<=3))
GROUP BY x1.[Employee ID], Employees.[Current Employee]
HAVING ((Count(x1.[Date of Test]))>=3);
obviously these two queries work but only for the last 3 tests.
How can I get all the employee ids for people that have tested over 34, but have not yet had 3 consecutive tests under 27 since their high result.
Start with the most recent date where you have a test of 34:
select [Employee ID], max([Date of Test]) as max34
from [Lead Results]
where [Test Result] > 34
group by [Employee ID];
Next, calculate the most recent date where there are three tests all below 27. This is a bit harder, but it can be done.
The following actually finds tests where the previous, next, and current are all less than 27. It then aggregates these to get the latest value.
select [Employee ID], max([Date of Test]) as MiddleTest27
from [Lead Results] as lr
where [Test Result] < 27 and
(select top 1 [Test Result]
from [Lead Results] as lr2
where lr2.[Employee ID] = lr.[Employee ID] and lr2.[Date of Test] < lr.[Date of Test]
order by [Date of Test] desc, id desc
) < 27 and
(select top 1 [Test Result]
from [Lead Results] as lr2
where lr2.[Employee ID] = lr.[Employee ID] and lr2.[Date of Test] > lr.[Date of Test]
order by [Date of Test] asc, id asc
) < 27
group by [Employee ID]
Next, we can combine these to get what you want: Employees whose most recent test is in the first query but not the second:
select e34.*
from (select [Employee ID], max([Date of Test]) as max34
from [Lead Results]
where [Test Result] > 34
group by [Employee ID]
) as e34 left join
(select [Employee ID], max([Date of Test]) as MiddleTest27
from [Lead Results] as lr
where [Test Result] < 27 and
(select top 1 [Test Result]
from [Lead Results] as lr2
where lr2.[Employee ID] = lr.[Employee ID] and lr2.[Date of Test] < lr.[Date of Test]
order by [Date of Test] desc, id desc
) < 27 and
(select top 1 [Test Result]
from [Lead Results] as lr2
where lr2.[Employee ID] = lr.[Employee ID] and lr2.[Date of Test] > lr.[Date of Test]
order by [Date of Test] asc, id asc
) < 27
group by [Employee ID]
) as e27
on e34.[Employee ID] = e27.[Employee ID]
where e27.[Employee ID] is NULL or e27.MiddleTest27 < e34.max34
That is, there is either no more recent "27" sequence or the last one predated the "34" sequence.