SQL WHERE/HAVING Condition - sql

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

Related

Get the Defect Type with the maximum Total Defect Qty

I have the following query which gets the sum of defect quantity per Defect Type :
SELECT
[Defect Type]
,YEAR([Date]) AS YearOfDefect
,SUM([Total Defect Qty]) AS [Sum] FROM SupplierQuality
GROUP BY [Defect Type],YEAR([Date])
This is the result :
I want to have the defect type with the maximum sum of total defect quantity like below :
DefectType YearOfDefect Sum
No Impact 2019 586780230
No Impact 2018 437989564
A simple option uses with ties:
SELECT TOP (1) WITH TIES
[Defect Type],
YEAR([Date]) AS YearOfDefect,
SUM([Total Defect Qty]) AS [Sum]
FROM SupplierQuality
GROUP BY [Defect Type], YEAR([Date])
ORDER BY RANK() OVER(PARTITION BY YEAR([Date]) ORDER BY SUM([Total Defect Qty]) DESC)
The downside is that this does not let you control the ordering of the resultset. If you really need that feature, then use a subquery:
SELECT *
FROM (
SELECT
[Defect Type],
YEAR([Date]) AS YearOfDefect,
SUM([Total Defect Qty]) AS [Sum],
RANK() OVER(PARTITION BY YEAR([Date]) ORDER BY SUM([Total Defect Qty]) DESC) rn
FROM SupplierQuality
GROUP BY [Defect Type], YEAR([Date])
) t
WHERE rn = 1
ORDER BY YearOfDefect
Making the assumption I make in the comments, and this is per year, then you can use ROW_NUMBER to get the "top" row per group:
WITH CTE AS(
SELECT [Defect Type],
YEAR([Date]) AS YearOfDefect,
SUM([Total Defect Qty]) AS [Sum]
FROM SupplierQuality
GROUP BY [Defect Type],
YEAR([Date]))
SELECT TOP (1) WITH TIES
[Defect Type],
YearOfDefect,
[Sum]
FROM CTE
ORDER BY ROW_NUMBER() OVER (PARTITION BY YearOfDefect ORDER BY [Sum] DESC);
Please also refer to another method:
with cte
as(SELECT
[Defect Type]
,YEAR([Date]) AS YearOfDefect
,SUM([Total Defect Qty]) AS [Sum] FROM SupplierQuality
GROUP BY [Defect Type],YEAR([Date]))
,cte2 as
(select YearOfDefect,max([Sum]) [Sum]
from cte
group by YearOfDefect)
select c1.[Defect Type],c2.YearOfDefect,c2.[Sum]
from cte c1
join c2
on c1.[Defect Type]=c2.[Defect Type] and c1.YearOfDefect=c2.YearOfDefect

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 aggregate and other fields showing in query

I have a query, where I need the MIN of a DateTime field and then I need the value of a corresponding field in the same row.
Now, I have something like this, however I cannot get Price field without putting it also in an aggregate clause, which is not what I want.
SELECT MIN([Registration Time]), Price FROM MyData WHERE [Product Series] = 'XXXXX'
I need the MIN of the Registration Time field and then I just want the corresponding Price field for that row, however how do I show that?
I do also need my WHERE clause as shown.
I'm sure I've overlooked something really obvious. Using SQL Server 2008
If you want just one record with [Registration Time], Price, it'd be as simple as this:
select top 1 [Registration Time], Price
from MyData
where [Product Series] = 'XXXXX'
order by [Registration Time]
If you want minimum [Registration Time] and corresponding Price for all [Product Series], then there's a few approaches, for example, using row_number() function:
with cte as (
select
[Registration Time], Price,
row_number() over(partition by [Product Series] order by [Registration Time]) as rn
from MyData
)
select
[Registration Time], Price, [Product Series]
where rn = 1

SQL Result Set Merge

I have a limitation where I can only send one result set to a reporting application at any one time, to produce an end report for a customer.
So a query like this
select
[AGENT],
[TRANSDATE],
[RECIPT NO],
[CUSTOMER NAME],
[ORDER NO] ,
[TRANS NO] ,
QUANTITY,
[AMOUNT COST],
From [Customer] C
However I need lots of totals at the bottom such as this query for some of the columns. I cannot make any changes to front end due to it being a legacy reporting application.
select
Sum ( QUANTITY ) as [SUM OF QUANTITY] ,
Sum ( AMOUNT COST ) AS [SUM OF AMOUNT COST]
From [Customer] C
Obviously I simplified the queries I am using. So the question is how to make 2 results sets one result set in SQL?
Union and union all failed due to date columns being defaulted if you use blank for a column in end application.
Rollup or Pivoting or CTE I kinda thought of but cannot see a solution yet.
what about windowed functions?
like...
select
[AGENT],
[TRANSDATE],
[RECIPT NO],
[CUSTOMER NAME],
[ORDER NO] ,
[TRANS NO] ,
QUANTITY,
[AMOUNT COST],
Sum ( QUANTITY ) over () as [SUM OF QUANTITY] ,
Sum ( [AMOUNT COST] ) over () AS [SUM OF AMOUNT COST]
From [Customer] C

Select top n records from each category within same table

I've a purchase detail table that has item id, purchase date, and item unit cost.
I want to get an avg of an item purchase cost by selecting latest top 2 records from each item id.
Item id, purchase date, unitprice
1 3/1/2012 10
1 3/11/2012 8
2 3/1/2012 10
2 3/11/2012 10
1 2/1/2012 9
3 3/1/2012 10
3 3/11/2012 1
3 3/12/2012 13
I'm using sql server 2008 r2
Try this:
;WITH CTE AS (
SELECT [Item id], [purchase date], unitprice,
ROW_NUMBER() OVER(PARTITION BY [Item id] ORDER BY [purchase date] DESC) rn
FROM your_table
)
SELECT [Item id], [purchase date], unitprice
FROM CTE
WHERE rn < 3
I'm not sure how can you calc avg with latest two records, but sure you can add GROUP BY to the query if you need.
Maybe something like that:
-- CTE here --
SELECT [Item id], AVG(unitprice)
FROM CTE
WHERE rn < 3
GROUP BY [Item id]
;WITH CTE AS (
SELECT [Item id]
, [purchase date]
, [unitprice]
, [avg] = AVG([unitprice]) OVER(PARTITION BY [Item id])
, [rnum] = ROW_NUMBER() OVER(PARTITION BY [Item id] ORDER BY [purchase date] DESC)
FROM T
)
SELECT [Item id], [purchase date], [unitprice], [avg]
FROM CTE
WHERE rnum < 3
SELECT AVG(unitprice) as price from yourtablename
where unitprice IN
(
SELECT TOP 3 (unitprice) from yourtablename
where itemid='1'
ORDER BY unitprice Desc
);
Get the itemid through dropdownlist or textbox.
Is't useful to you ?