duplicate values in DB2 - sql

I am working on DB2.
There are duplicate rows in the table. I need to extract data where there is different value in 2nd column for same value in 1st column.
there are column other than these in table but only need to consider these.
for example:
NBR
SE_NBR
123
56
123
56
123
56
248
75
248
75
To extract
NBR
SE_NBR
456
12
456
34
456
11
135
77
135
88

here is one way using window function:
select * from
(
select *, min(SE_NBR) over (partition by NBR) minnbr, max(SE_NBR) over (partition by NBR) maxnbr
from nbrtable
) t
where minnbr <> maxnbr
if window function is not supported:
select * from tableName t1
where exists (
select 1 from tablename t2
where t1.NBR = t2.NBR
group by t2.nbr
having count(distinct SE_NBR) > 1
)
db<>fiddle here

You can do:
select *
from t
where nbr in (
select nbr from t group by nbr having count(distinct se_nbr) > 1
)

Related

Select max value without group by [duplicate]

This question already has an answer here:
SQL Max(date) without group by
(1 answer)
Closed 2 years ago.
I need to help to get a max value for each id. Simple table is just shown below,
ID Value
---------------
111 150
112 110
111 100
113 120
115 130
111 180
112 190
What I want too see in the output:
ID Value
---------------
111 180
112 190
111 180
113 120
115 130
111 180
112 190
I do not want to group by each id, I want all of them in the output.
I think you want window functions:
select t.*, max(value) over (partition by id) as max_id
from t;
This answers the question. I'm not sure what the sample data has to do with the question.
You could also correlated subquery in the SELECT list:
SELECT
id,
(SELECT
max(value)
FROM
tbl t2
WHERE
t2.id = t1.id) AS value
FROM
tbl t1
If you do not want to use the MAX function at all then you can use the NOT EXISTS as follows:
SELECT Y.ID, R.VALUE
FROM YOUR_TABLE Y
JOIN ( SELECT DISTINCT ID, VALUE
FROM YOUR_TABLE T
WHERE NOT EXISTS ( SELECT 1
FROM YOUR_TABLE TT
WHERE TT.ID = T.ID
AND TT.VALUE > T.VALUE
)
) R ON Y.ID = R.ID

How to use this in sql -- > max(sum (paid * quantity )) to solve a query

How to get the max value order of each customer ?
select num, max(sum(paid*quantity))
from orders join
pizza
using (order#)
group by customer#;
table
num orderN price
-------- --- -------
1 109 30
1 118 25
3 101 30
3 115 27
4 107 23
5 100 17
5 129 16
output req-
num Pnum price
-------- --- -------
1 109 30
3 101 30
4 107 23
5 100 17
You want to select the record having the highest price in each group of nums.
If your RDBMS supports window functions, that's straight forward with ROW_NUMBER() :
SELECT num, pnum, price
FROM (
SELECT t.*, ROW_NUMBER OVER(PARTITION BY num ORDER BY price DESC) rn
FROM mytable t
) x
WHERE rn = 1
Else, you can take the following approach, that uses a NOT EXISTS condition with a correlated subquery to ensure that the record being joined in the one with the highest price for the current num :
SELECT num, pnum, price
FROM mytable t
WHERE NOT EXISTS (
SELECT 1 FROM mytable t1 WHERE t1.num = t.num AND t1.price > t.price
)

Removing pairs of transactions

I am attempting to remove transactions that have been reversed from a table. the table has Account, Date, Amount and Row. If a transaction has been reversed Account will match and Amount will be inverse of each other.
Example Table
Account Date Amount Row
12 1/1/18 45 72 -- Case 1
12 1/2/18 50 73
12 1/2/18 -50 74
12 1/3/18 52 75
15 1/1/18 51 76 -- Case 2
15 1/2/18 51 77
15 1/2/18 -51 78
15 1/2/18 51 79
18 1/2/18 50 80 -- Case 3
18 1/2/18 50 81
18 1/2/18 -50 82
18 1/2/18 -50 83
18 1/3/18 50 84
18 1/3/18 50 85
20 1/1/18 57 88 -- Case 4
20 1/2/18 57 89
20 1/4/18 -57 90
20 1/5/18 57 91
Desired Results Table
Account Date Amount Row
12 1/1/18 45 72 -- Case 1
12 1/3/18 52 75
15 1/1/18 51 76 -- Case 2
15 1/2/18 51 79
18 1/3/18 50 84 -- Case 3
18 1/3/18 50 85
20 1/1/18 57 88 -- Case 4
20 1/5/18 57 91
Removing all instances of inverse transactions does not work when there are multiple transactions when all other columns are the same. My attempt was to count all duplicate transactions, count of all inverse duplicate transactions, subtracting those to get the number of rows I needed from each transactions group. I was going to pull the first X rows but found in most cases I want the last X rows of each group, or even a mix (the first and last in Case 2).
I either need a method of removing pairs from the original table, or working from what I have so far, a method of distinguishing which transactions to pull.
Code so far:
--adding row Numbers
with a as (
select
account a,
date d,
amount f,
row_number() over(order by account, date) r
from table),
--counting Duplicates
b as (
select a.a, a.f, Dups
from a join (
select a, f, count(*) Dups
from a
group by a.a, a.f
having count(*)>1
) b
on a.a=b.a and
b.f=a.f
where a.f>0
),
--counting inverse duplicates
c as (
select a.a, a.f, InvDups
from a join (
select a, f, count(*) InvDups
from a
group by a.a, a.f
having count(*)>1
) b
on a.a=b.a and
-b.f=a.f
where a.f>0
),
--combining c and d to get desired number of rows of each transaction group
d as (
select
b.a, b.f, dups, InvDups, Dups-InvDups TotalDups
from b join c
on b.a=c.a and
b.f=c.f
),
--getting the number of rows from the beginning of each transaction group
select d.a, d.d, d.f
from
(select
a, d, f, row_number() over (group by a, d, f) r2
from a) e
join d
on e.a=d.a and
TotalDups<=r2
You can try this.
SELECT T_P.* FROM
( SELECT *, ROW_NUMBER() OVER(PARTITION BY Account, Amount ORDER BY [Row] ) RN from #MyTable WHere Amount > 0 ) T_P
LEFT JOIN
( SELECT *, ROW_NUMBER() OVER(PARTITION BY Account, Amount ORDER BY [Row] ) RN from #MyTable WHere Amount < 0 ) T_N
ON T_P.Account = T_N.Account
AND T_P.Amount = ABS(T_N.Amount)
AND T_P.RN = T_N.RN
WHERE
T_N.Account IS NULL
The following handles your three cases:
with t as (
select t.*,
row_number() over (partition by account, date, amount order by row) as seqnum
from table t
)
select t.*
from t
where not exists (select 1
from t t2
where t2.account = t.account and t2.date = t.date and
t2.amount = -t.amount and t2.seqnum = t.seqnum
);
Use This
;WITH CTE
AS
(
SELECT
[Row]
FROM YourTable YT
WHERE Amount > 0
AND EXISTS
(
SELECT 1 FROM YourTable WHERE Account = YT.Account
AND [Date] = YT.[Date]
AND (Amount+YT.Amount)=0
)
UNION ALL
SELECT
[Row]
FROM YourTable YT
WHERE Amount < 0
AND EXISTS
(
SELECT 1 FROM YourTable WHERE Account = YT.Account
AND [Date] = YT.[Date]
AND (Amount+YT.Amount)>0
)
)
SELECT * FROM YourTable
WHERE EXISTS
(
SELECT 1 FROM CTE WHERE [Row] = YourTable.[Row]
)

SQL Loop to increment numbers

I'm struggling coming up with a way to solve this answer. I want to start at a specific value and keep increasing it by 1 every time a new line.
For example, if I have a table like so.
90
93
110
87
130
Etc..
I want to select the number 87 and then keep incrementing up from there but also read if the incremented number is there and skip it.
I am just struggling with trying to put the right logic together in my head. I know I need a while loop to keep reading through the table but I can't think of the proper way to go about it. Just looking for some suggestions to push me in the right direction.
Edit: I am using T-SQL for MSFT SQL Server 2012.
Here is an example of what the output should look like
90
93
110
87
130
88
89
91
92
94
It would skip over adding 90 and 93 because they already exist in the table.
I hope that makes sense to you guys.
I do it all in one recursive CTE and I make it so you can use order by and guarantee your results are returned in the correct order.
For the recursion, you can either choose and start and end number or #desiredNumberOfNewValues(keep in mind, it doesn't account for repeats). Let me know if you have any questions or need anything else.
DECLARE #yourTable TABLE (nums INT);
INSERT INTO #yourTable
VALUES (90),(93),(110),(87),(130);
DECLARE #Specific_Number INT = 87;
DECLARE #Last_Number INT = 94;
DECLARE #DesiredNumberOfNewValues INT = 7;
WITH CTE_Numbers
AS
(
SELECT 1 AS order_id,nums, 1 AS cnt
FROM #yourTable
UNION ALL
SELECT 2,
CASE
WHEN #Specific_Number + cnt NOT IN (SELECT * FROM #yourTable) --if it's not already in the table, return it
THEN #Specific_Number + cnt
ELSE NULL -- if it is in the table, return NULL
END,
cnt + 1
FROM CTE_Numbers
WHERE nums = #Specific_Number
--OR (cnt > 1 AND #Specific_Number + cnt < #Last_Number) --beginning and end(option 1)
OR (cnt > 1 AND cnt <= #DesiredNumberOfNewValues) --number of new values(option 2)
)
SELECT order_id,nums
FROM CTE_Numbers
WHERE nums IS NOT NULL
ORDER BY order_id,nums
Results:
order_id nums
----------- -----------
1 87
1 90
1 93
1 110
1 130
2 88
2 89
2 91
2 92
2 94
You might be able to do this with some modifications by using Numbers table. In SQL Server, you could do the following. Assuming Test has the data. To create Numbers table, please refer to the following link.
http://dataeducation.com/you-require-a-numbers-table/
SELECT n.Number,t.ColB
FROM Numbers n
LEFT JOIN Test t
ON n.Number = t.ColA
Where n.Number < (SELECT MAX(COLA) FROM Test t)
WITH Numbers_CTE (Number)
AS
(
SELECT 1 AS Number
UNION ALL
SELECT Number+1 FROM Numbers_CTE
)
SELECT top 10 *
FROM Numbers_CTE n
LEFT JOIN <TABLE> t ON t.ID=n.Number
WHERE t.ID IS NULL
AND n.Number BETWEEN 5 AND 100
There is a system table you can use for numbers called master..spt_values.
DECLARE sample TABLE
DECLARE #tbl TABLE(Id INT)
INSERT statement
INSERT INTO #tbl VALUES (90)
,(93)
,(110)
,(87)
,(130)
You can easily make a UNION to remove duplicates value you have in your table and ORDER it within a CTE
DECLARE #number INT = 87
;WITH C AS(
SELECT Id, Row_Id, ROW_NUMBER() OVER(PARTITION BY Id ORDER BY Id) AS Rn FROM (
SELECT 1 AS Row_Id, Id FROM #tbl
UNION
SELECT 2 AS Row_Id, number
FROM master..spt_values
WHERE [type] = 'P'
AND number >= #number
) t
)
SELECT Id FROM C
WHERE Rn = 1
ORDER BY Row_Id, Id
Output
Id
----
87
90
93
110
130
88
89
91
92
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
111
112
113
114
.
.
.
SQLFiddle

T-SQL How to select rows without duplicate values from one column?

I have a table with 2 columns ID, ID_PROJ_CSR
The content of that table is:
ID ID_PROJ_CSR
------------------
747 222 <
785 102
786 222 <
787 223
788 224
I want to select the ID, but if any value from ID_PROJ_CSR is a duplicate, I need to select any ID of the rows that contains that duplicate value (in that example, select ID 747 OR 786
I try:
SELECT * FROM my_table tab
WHERE tab.id_proj_csr = (SELECT TOP 1 id_proj_csr
FROM my_table mt
WHERE mt.id_proj_csr = tab.id_proj_csr)
You need to GROUP BY:
SELECT MAX(ID) as [ID], ID_PROJ_CSR
FROM my_table
GROUP BY ID_PROJ_CSR
Here's the case of omitting anything that has a duplicate value, so you'll only get rows that don't have duplicates:
SELECT *
FROM my_table
GROUP BY ID_PROJ_CSR
HAVING count(ID_PROJ_CSR) = 1;