Row Filter Using Distinct - sql

This is master table Query
Select *
from AC_TAB
where AC_ID = 7 ;
AC_PK AC_ID TYPE STATUS INS_DATE VALID
102 7 0 0 3/21/2012 3:35:08 PM 0
103 7 1 0 3/21/2012 3:35:08 PM
104 7 2 1 3/21/2012 3:35:08 PM
I am joining this table with txn table using ac_id. Since here its having 3 rows for ac_id 7 , my txn table returning 3 times. how to restrict this. since i want to return only one irrespective of type
MY Txn Query
Select txn_id, amount
from txn_hdr , ac_tab
where txn_ac_id = ac_id ;
txn_id amount
1 200
1 200
3 100
3 100

It is not actually clear what you need but it sounds like you only want to return one record per ac_id from the AC_TAB. If so, then there are a few ways that you can do this.
Using a subquery:
select *
from
(
select max(INS_DATE) INS_DATE, AC_ID
from ac_tab
group by AC_ID
) a
inner join txn_hdr t
on a.ac_id = t.ac_id;
Or with CTE using a row_number():
;with cte as
(
select a.ins_date, a.ac_id, t.amount, row_number()
over(partition by a.ac_id order by a.ins_date desc) rn
from ac_tab a
inner join txn_hdr t
on a.ac_id = t.ac_id
)
select *
from cte
where rn = 1;
Or with a row_number() in a subquery:
select *
from
(
select a.ins_date, a.ac_id, t.amount, row_number()
over(partition by a.ac_id order by a.ins_date desc) rn
from ac_tab a
inner join txn_hdr t
on a.ac_id = t.ac_id
) x
where rn = 1

You can do this way :
Select distinct txn_id, amount
from txn_hdr , ac_tab
where txn_ac_id = ac_id ;

Related

select maximum value and minimal date from it's corresponding dates

I have the following table:
ClientId | CalculationDate | TransactedAmount |
1 13/02/2015 3
1 14/02/2015 3
2 14/02/2015 5
3 15/03/2015 6
2 15/03/2015 5
As a result I want table which contains ClientId and minimal Months passed since
maximum amount were transacted for each clientId.
How can i do that?
SELECT DISTINCT ClientId , MaxAmount.TransactedAmount , DATEDIFF(MONTH,MaxAmount.CalculationDate ,getdate())
FROM TABLENAME T1
CROSS APPLY(SELECT TOP 1 TransactedAmount ,CalculationDate
FROM TABLENAME T2
WHERE T1.ClientId = T2.ClientId
ORDER BY TransactedAmount DESC) MaxAmount
Using Window Function like Row_Nummber() we can achieve the same
;With cte(ClientId , CalculationDate , TransactedAmount )
AS
(
SELECT 1,'13/02/2015',3 UNION ALL
SELECT 1,'14/02/2015',3 UNION ALL
SELECT 2,'14/02/2015',5 UNION ALL
SELECT 3,'15/03/2015',6 UNION ALL
SELECT 2,'15/03/2015',5
)
SELECT ClientId , CalculationDate,TransactedAmount From
(
SELECT ClientId , CalculationDate ,MAX(TransactedAmount)OVER(Partition by ClientId Order by CalculationDate) As TransactedAmount ,
ROW_NUMBER()OVER(Partition by ClientId Order by CalculationDate) AS RNo From cte
)Dt
WHERE Dt.RNo=1

Sorting sub-queries in SQL

I've been trying to a query working in SQL 2012 which I'm almost certain I am over complicating
I have a table which stores an order number, item numbers (multiple per order), status codes (multiple per item) and a timestamp
So basically something like this
Order Item Status
1 1 1
1 1 2
2 1 1
2 1 2
2 1 3
3 1 3
3 2 1
3 2 2
Within my query (using this table as the example), I need see the following 1 entry for each line and item but only showing the highest available status... BUT not if the status is 3
So in this case, I'd want to see
Order Item Status
1 1 2
3 2 2
The issue I had is that the query itself works... but it returns the FIRST status code it finds. Not the highest one. So I end up with
Order Item Status
1 1 1
3 2 1
Here's the full expanded code snippet
with summary as (
select a.order_no as order_no, a.item_no as item_no, a.timestamp as timestamp,
max(a.status_code) as status_code, row_number() over (partition by order_no
order by item_no asc) as rn
from db.ordhist a
where a.order_no > 120400000 and a.order_no < 120800000
and a.timestamp < Dateadd(DD,-3,GETDATE() )
and a.status_code >= 133
and not exists (
select b.order_no, b.item_no
from db.ordhist b
where b.status_code in (137,170,201,999)
and b.order_no = a.order_no
and b.item_no = a.item_no)
and not exists (
select c.order_no
from db.ordhist c
where c.status_code = 6
and c.order_no = a.order_no)
group by a.order_no, a.item_no, a.timestamp)
select * from summary where rn = 1
I think you don't need ROW_NUMBER just use a GROUP BY with HAVING MAX([Status])<>3:
SELECT [Order],[Item],MAX([Status])
FROM Table_Name
GROUP BY [Order],[Item]
HAVING MAX([Status])<>3
Ok I think I may have answered my own question.... by removing the grouping within the "summary" and doing grouping in the final results query instead
-- Produced (or higher) but not Delivery Noted --
with summary as (
select a.order_no as order_no, a.item_no as item_no, a.timestamp as timestamp, a.status_code as status_code
from db.ordhist a
where a.order_no > 120400000 and a.order_no < 120800000
and a.timestamp < Dateadd(DD,-3,GETDATE() )
and a.status_code >= 133
and not exists (
select b.order_no, b.item_no
from db.ordhist b
where b.status_code in (137,170,201,999)
and b.order_no = a.order_no
and b.item_no = a.item_no)
and not exists (
select c.order_no
from db.ordhist c
where c.status_code = 6
and c.order_no = a.order_no))
select order_no, item_no, timestamp, max(status_code) from summary
group by order_no, item_no, timestamp
order by status_code

Any other alternative to write this SQL query

I need to select data base upon three conditions
Find the latest date (StorageDate Column) from the table for each record
See if there is more then one entry for date (StorageDate Column) found in first step for same ID (ID Column)
and then see if DuplicateID is = 2
So if table has following data:
ID |StorageDate | DuplicateTypeID
1 |2014-10-22 | 1
1 |2014-10-22 | 2
1 |2014-10-18 | 1
2 |2014-10-12 | 1
3 |2014-10-11 | 1
4 |2014-09-02 | 1
4 |2014-09-02 | 2
Then I should get following results
ID
1
4
I have written following query but it is really slow, I was wondering if anyone has better way to write it.
SELECT DISTINCT(TD.RecordID)
FROM dbo.MyTable TD
JOIN (
SELECT T1.RecordID, T2.MaxDate,COUNT(*) AS RecordCount
FROM MyTable T1 WITH (nolock)
JOIN (
SELECT RecordID, MAX(StorageDate) AS MaxDate
FROM MyTable WITH (nolock)
GROUP BY RecordID)T2
ON T1.RecordID = T2.RecordID AND T1.StorageDate = T2.MaxDate
GROUP BY T1.RecordID, T2.MaxDate
HAVING COUNT(*) > 1
)PT ON TD.RecordID = PT.RecordID AND TD.StorageDate = PT.MaxDate
WHERE TD.DuplicateTypeID = 2
Try this and see how the performance goes:
;WITH
tmp AS
(
SELECT *,
RANK() OVER (PARTITION BY ID ORDER BY StorageDate DESC) AS StorageDateRank,
COUNT(ID) OVER (PARTITION BY ID, StorageDate) AS StorageDateCount
FROM MyTable
)
SELECT DISTINCT ID
FROM tmp
WHERE StorageDateRank = 1 -- latest date for each ID
AND StorageDateCount > 1 -- more than 1 entry for date
AND DuplicateTypeID = 2 -- DuplicateTypeID = 2
You can use analytic function rank , can you try this query ?
Select recordId from
(
select *, rank() over ( partition by recordId order by [StorageDate] desc) as rn
from mytable
) T
where rn =1
group by recordId
having count(*) >1
and sum( case when duplicatetypeid =2 then 1 else 0 end) >=1

JOIN table when selecting a max value of columns

I have the below table structure that is successfully getting the max column value of a table for each CommentID. But I want to JOIN the table tbComment with tbCommentBreadcrumb where CommentID is the key.
tbComment
CommentID IsLocked
1 0
2 0
3 1
4 0
5 1
tbCommentBreadcrumb
CommentStatusID CommentID StatusTypeID
105 1 1
106 1 4
107 2 1
108 3 1
109 3 4
110 4 1
112 5 1
112 5 4
Here's what I have working:
SELECT *
FROM
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY CommentID ORDER BY CreateDateTime desc) as rn
FROM
tbCommentBreadCrumb
WHERE
CommentStatusTypeID = 4
AND CreateDateTime <= {ts '2014-02-09 09:44:57'}
) t
WHERE
t.rn = 1
ORDER BY
CommentStatusID DESC
This returns over a hundred records and I want to further refine the query by only getting the records where the above query is true but also that each of the CommentID in the table tbComment is locked. Basically not sure where to JOIN tbComment and put the AND tbComment.CommentIsLocked = 1
You are quite close :-)
SELECT t.*
FROM
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY CommentID ORDER BY CreateDateTime desc) as rn
FROM
tbCommentBreadCrumb
WHERE CommentStatusTypeID = 4
AND CreateDateTime <= {ts '2014-02-09 09:44:57'}
) t
JOIN tbComment c ON t.CommentID = c.CommentID
WHERE
t.rn = 1
AND c.CommentIsLocked = 1
ORDER BY CommentStatusID DESC
;With CTE
AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY CommentID ORDER BY CreateDateTime desc) as rn
FROM tbCommentBreadCrumb
WHERE CommentStatusTypeID = 4
AND CreateDateTime <= {ts '2014-02-09 09:44:57'}
)
SELECT *
FROM CTE C INNER JOIN tbComment TC
ON C.CommentID = TC.CommentID
WHERE C.rn = 1
ORDER BY C.CommentStatusID DESC

left join without duplicate values using MIN()

I have a table_1:
id custno
1 1
2 2
3 3
and a table_2:
id custno qty descr
1 1 10 a
2 1 7 b
3 2 4 c
4 3 7 d
5 1 5 e
6 1 5 f
When I run this query to show the minimum order quantities from every customer:
SELECT DISTINCT table_1.custno,table_2.qty,table_2.descr
FROM table_1
LEFT OUTER JOIN table_2
ON table_1.custno = table_2.custno AND qty = (SELECT MIN(qty) FROM table_2
WHERE table_2.custno = table_1.custno )
Then I get this result:
custno qty descr
1 5 e
1 5 f
2 4 c
3 7 d
Customer 1 appears twice each time with the same minimum qty (& a different description) but I only want to see customer 1 appear once. I don't care if that is the record with 'e' as a description or 'f' as a description.
First of all... I'm not sure why you need to include table_1 in the queries to begin with:
select custno, min(qty) as min_qty
from table_2
group by custno;
But just in case there is other information that you need that wasn't included in the question:
select table_1.custno, ifnull(min(qty),0) as min_qty
from table_1
left outer join table_2
on table_1.custno = table_2.custno
group by table_1.custno;
"Generic" SQL way:
SELECT table_1.custno,table_2.qty,table_2.descr
FROM table_1, table_2
WHERE table_2.id = (SELECT TOP 1 id
FROM table_2
WHERE custno = table_1.custno
ORDER BY qty )
SQL 2008 way (probably faster):
SELECT custno, qty, descr
FROM
(SELECT
custno,
qty,
descr,
ROW_NUMBER() OVER (PARTITION BY custno ORDER BY qty) RowNum
FROM table_2
) A
WHERE RowNum = 1
If you use SQL-Server you could use ROW_NUMBER and a CTE:
WITH CTE AS
(
SELECT table_1.custno,table_2.qty,table_2.descr,
RN = ROW_NUMBER() OVER ( PARTITION BY table_1.custno
Order By table_2.qty ASC)
FROM table_1
LEFT OUTER JOIN table_2
ON table_1.custno = table_2.custno
)
SELECT custno, qty,descr
FROM CTE
WHERE RN = 1
Demolink