count of a column in the result set on which distinct is already applied - sql

Consider the table Property.
KeyIdNum|Property|IdNum
1 12 1234
1 12 1234
1 44 1234
1 12 1234
1 56 1234
2 12 4567
3 12 6789
3 56 6789
3 12 6789
4 44 3434
5 12 4444
6 44 9999
6 44 9999
It contains property num associated with each id num.But it contains duplicates.
I applied distinct to avoid duplicates.
select distinct KeyIdNum,Property,IdNum from Property.
So i got the result as :
KeyIdNum |Property |IdNum
1 12 1234
1 44 1234
1 56 1234
2 12 4567
3 12 6789
3 56 6789
4 44 3434
5 12 4444
6 44 9999
But now I want to `select( after applying distinct) ,the KeyIdNum (or IdNum) which are coming more than one time in the distinct result set shown above.
Please help me on this.I am not able to find a way to get the count of a column in the distinct result set using a single query.

Below query will result of KeyidNum , its number of row count.
select KeyIdNum,count(KeyIdNum)
From (
select distinct KeyIdNum,Property,IdNum from Property )
group by KeyIdNum

select KeyIdNum,count(KeyIdNum) as count
From (
select distinct KeyIdNum,Property,IdNum from Table19 )A
group by KeyIdNum
output
KeyIdNum count
1 3
2 1
3 2
4 1
5 1
6 1

This answer uses t-sql:
SELECT x
FROM ( SELECT * ,
rn = rownumber() OVER ( PARTITION BY keyidnum, idnum
ORDER BY keyidnum, idnum )
FROM tblProperty
) x
WHERE rn > 1

Related

SQL Temp table Array to perfrom rolling caluclations

I wish to use some sort of SQL array to subtract values from a certain row (QTYOnHand) that decreases that row value every time and throws it into a rolling calculation for the other rows. I've been thinking of some sort of Self Join/Temp Table solution, but not sure how to formulate. Also, All the results will be partitioned by the ItemID below. Help would be appreciated.
Here's some data, If I do a simple row by row subtraction I will get this: 17-3 = 14, 17-5 = 12 and so on.
(Item_ID) (ItemQty) (QTYOnHand) (QtyOnHand - ItemQty)
123 3 17 14
123 5 17 12
123 4 17 13
456 7 12 5
456 8 12 4
456 2 12 10
456 3 12 9
789 2 6 4
789 2 6 4
789 2 6 4
These are the results that I want, where I subtract every next value from the new QTYOnHand-ItemQty column value. Looks like 17-3 then 14 -5 then 9 -4 for Item_ID (123):
(Item_ID) (ItemQty) (QTYOnHand) (QtyOnHand - ItemQty)
123 3 17 14
123 5 17 9
123 4 17 5
456 7 12 5
456 8 12 -3
456 2 12 -5
456 3 12 -8
789 2 6 4
789 2 6 2
789 2 6 0
try the following:
;with cte as
(
select *, ROW_NUMBER() over (partition by Item_ID order by Item_ID) rn
from YourTable
)
, cte2 as
(
select Item_ID, ItemQty, QTYOnHand, Case when rn = 1 then QTYOnHand else 0 end - ItemQty as calc, rn
from cte
)
select Item_ID, ItemQty, QTYOnHand, sum(calc) over (partition by Item_ID order by rn) as [QtyOnHand - ItemQty]
from cte2 t1
Please find the db<>fiddle here.

T SQL CTE Previous Row Calculation

I'm using SQL Server 2016.
I have the below table:
SKU Shop Week ShopPrioirty Replen Open_Stk Open_Stk Calc
111 100 1 1 0 17 NULL
111 200 1 2 2 NULL NULL
111 300 1 3 0 NULL NULL
111 400 1 4 0 NULL NULL
222 100 2 1 5 17 NULL
222 200 2 2 5 NULL NULL
222 300 2 3 5 NULL NULL
222 400 2 4 5 NULL NULL
This is the desired result:
SKU Shop Week ShopPrioirty Replen Open_Stk Open_Stk Calc
111 100 1 1 0 17 17
111 200 1 2 2 NULL 17
111 300 1 3 0 NULL 15
111 400 1 4 0 NULL 15
222 100 2 1 20 17 17
222 200 2 2 15 NULL 12
222 300 2 3 12 NULL 7
222 400 2 4 10 NULL 2
I need to update the 'Open_Stk Calc' based on the previous row:
'Open_Stk Calc' - IIF('Replen'<=IIF('Open_Stk'>=0,'Open_Stk',0),'Replen',0)
I am using a CTE to update a row based on a calculation of the previous rows. This is my SQL:
;WITH CTE AS
(
SELECT
SKU,
[Shop],
[Week],
[Store_Priority],
[Replen],
[Open_Stk],
[Open_Stk Calc],
FIRST_VALUE([Open_Stk]) OVER ( PARTITION BY [SKU] ,[Week] ORDER BY [Store_Priority] ROWS UNBOUNDED PRECEDING)
-
ISNULL(SUM(IIF([Replen] <= IIF([Open_Stk]>=0,[Open_Stk],0),[Replen],0))
OVER (PARTITION BY [SKU] ,[Week] ORDER BY [Store_Priority] ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), 0) AS CurrentStock
FROM [tblTEST])
UPDATE CTE
SET [Open_Stk Calc] = CurrentStock
However, this produces the following result:
SKU Shop Week ShopPrioirty Replen Open_Stk Open_Stk Calc
111 100 1 1 0 17 17
111 200 1 2 2 NULL 17
111 300 1 3 0 NULL 17
111 400 1 4 0 NULL 17
And not the desired result - where have I gone wrong?
As one can see in the MS documentation, the OVER clauses supports specific kind of functions:
Ranking functions
Aggregate functions
Analytic functions
NEXT VALUE FOR function
None of them include IIF, as Luis Cazares noted in their comment.
Your code indicates you do have a clue about what you are doing - maybe you forgot to put your IIF inside a SUM?

Running total of rows by ID

I have a list of IDs, transactions, and the date of those transactions. I want to create a count of each transaction within each ID.
The starting table I have is looks something like this:
id trxn_dt trxn_amt
1 10/31/2014 58
1 11/9/2014 34
1 12/10/2014 12
2 7/8/2014 78
2 11/20/2014 99
3 1/5/2014 120
4 2/17/2014 588
4 2/18/2014 8
4 3/9/2014 65
4 4/25/2014 74
and I want the end result to look something like this:
id trxn_dt trxn_amt trxn_count
1 10/31/2014 58 1
1 11/9/2014 34 2
1 12/10/2014 12 3
2 7/8/2014 78 1
2 11/20/2014 99 2
3 1/5/2014 120 1
4 2/17/2014 588 1
4 2/18/2014 8 2
4 3/9/2014 65 3
4 4/25/2014 74 4
Count(distinct(id)) would only give me the overall number of distinct IDs and not a running total by each ID that restarts at each new ID.
Thank you!
In SQL-Server you can use ROW_NUMBER in following:
SELECT id,
trxn_dt,
trxn_amt,
ROW_NUMBER() OVER(PARTITION BY Id ORDER BY Id, trxn_dt) AS trxn_count
FROM StarningTable
In MySQL you can do in following:
SELECT
t.id,
t.trxn_dt,
t.trxn_amt,
#cur:= IF(id=#id, #cur+1, 1) AS RowNumber,
#id := id
FROM
StarningTable t
CROSS JOIN
(SELECT #id:=(SELECT MIN(id) FROM StarningTable t), #cur:=0) AS init
ORDER BY
t.id
using Row_number we can achieve this
Select *,
ROW_NUMBER()OVER(PARTITION BY id ORDER BY (SELECT NULL))trxn_count
from Transactions

Access SQL - Select only the last sequence

I have a table with an ID and multiple informative columns. Sometimes however, I can have multiple data for an ID, so I added a column called "Sequence". Here is a shortened example:
ID Sequence Name Tel Date Amount
124 1 Bob 873-4356 2001-02-03 10
124 2 Bob 873-4356 2002-03-12 7
124 3 Bob 873-4351 2006-07-08 24
125 1 John 983-4568 2007-02-01 3
125 2 John 983-4568 2008-02-08 13
126 1 Eric 345-9845 2010-01-01 18
So, I would like to obtain only these lines:
124 3 Bob 873-4351 2006-07-08 24
125 2 John 983-4568 2008-02-08 13
126 1 Eric 345-9845 2010-01-01 18
Anyone could give me a hand on how I could build a SQL query to do this ?
Thanks !
You can calculate the maximum sequence using group by. Then you can use join to get only the maximum in the original data.
Assuming your table is called t:
select t.*
from t join
(select id, MAX(sequence) as maxs
from t
group by id
) tmax
on t.id = tmax.id and
t.sequence = tmax.maxs

How to find all (group-based) rows containing MIN/MAX values for a particular column in SQL Server?

I have temporary table (#TempPackages) which looks like this:
EntryId (PK) PackageId SubProductID SubProductSequence
1 1111 17 3
2 1111 28 4
3 1111 33 1
4 1111 67 5
5 1111 122 2
6 2222 18 4
7 2222 29 5
8 2222 33 9
9 2222 103 7
10 2222 99 11
11 3333 256 5
12 3333 333 6
13 3333 789 3
14 3333 1023 2
15 3333 9845 1
I need a query which will give me the rows with the minimum/maximum SubProductSequence value for each unique PackageId. For the table above, the query would return this:
EntryId (PK) PackageId SubProductID SubProductSequence
3 1111 33 1
4 1111 67 5
6 2222 18 4
10 2222 99 11
12 3333 333 6
15 3333 9845 1
The EntryId column was something that I added while trying to solve this, as it gives me a unique column to join the same table on to (to ensure I still only end up with 15 rows in my joined table).
I tried this - just to get the MIN():
SELECT
*
FROM
#TempPackages p1
INNER JOIN
#TempPackages p2 ON p1.EntryId = p2.EntryId
AND p1.SubProductSequence = (
SELECT
MIN(SubProductSequence)
FROM
#DeparturesToUpdate)
Obviously this is wrong, because the INNER JOIN is superfluous and the SELECT MIN() clause is wrong as it selects the rows with the minimum overall sequence numbers, not the minimum sequence numbers per package.
Any suggestions about the best way to do this?
One way is to use the ROW_NUMBER() function:
SELECT
EntryId
, PackageId
, SubProductID
, SubProductSequence
FROM
( SELECT
EntryId
, PackageId
, SubProductID
, SubProductSequence
, ROW_NUMBER() OVER (PARTITION BY PackageId
ORDER BY SubProductSequence ASC)
AS rna
, ROW_NUMBER() OVER (PARTITION BY PackageId
ORDER BY SubProductSequence DESC)
AS rnd
FROM
#TempPackages
) AS tmp
WHERE
rna = 1
OR rnd = 1 ;
ROW_NUMBER() is a ranking function that is used with OVER clause. What it basically does in this case, is it groups the rows with same PackageId (that is done with the PARTITION BY PackageId), then orders them by SubProductSequence (ascending or descending) and assigns a row_number, starting from 1 for each packageId.
So, the subquery would return this, if it was run alone:
EntryId (PK) PackageId SubProductID SubProductSequence rna rnd
3 1111 33 1 1 5
5 1111 122 2 2 4
1 1111 17 3 3 3
2 1111 28 4 4 2
4 1111 67 5 5 1
6 2222 18 4 1 5
7 2222 29 5 2 4
9 2222 103 7 3 3
8 2222 33 9 4 2
10 2222 99 11 5 1
15 3333 9845 1 1 5
14 3333 1023 2 2 4
13 3333 789 3 3 3
11 3333 256 5 4 2
12 3333 333 6 5 1
The WHERE condition added in the external query is obvious afterwards.
Improving on Bohemian's idea -
;WITH MinMax AS
(SELECT PackageId ,
MIN(SubProductSequence) [Min],
MAX(SubProductSequence) [Max]
FROM #TempPackages
GROUP BY PackageId )
SELECT EntryId, SubProductSequence, TP.PackageId, SubProductID FROM #TempPkges TP
INNER JOIN MinMax MM ON TP.PackageId = MM.PackageId
AND (SubProductSequence = MM.[Min] OR SubProductSequence = MM.[Max])
And then, you can add your own ORDER BY
WITH t1 AS
(SELECT PackageId,MIN(SubProductSequence) minm,MAX(SubProductSequence) maxm
FROM ##TempPackages
GROUPBY PackageId
)
SELECT pk.EntryId, pk.PackageId,pk.SubProductID, pk.SubProductSequence
FROM ##TempPackages pk INNER JOIN t1
ON pk.PackageId = t1.PackageId
WHERE pk.SubProductSequence = t1.minm OR
pk.SubProductSequence = t1.maxm