I have following table which is having duplicate record with respect to different fields:
CREATE TABLE Student1
(`id` int,`status` int,`amount` int , `Name` varchar(10), `date` varchar(55))
;
INSERT INTO Student1
(`id`,`status`,`amount`, `Name`, `date`)
VALUES
(1,0,4500, 'ram', '04/02/2012'),
(2,0,2000, 'shyam', '05/09/2013'),
(4,0,1500, 'ghanshyam', '08/11/2014'),
(3,0,4500, 'gopal', '04/02/2012'),
(2,0,8000, 'radheshyam', '15/11/2013'),
(4,1,1500, 'ghanshyam', '18/10/2015'),
(1,1,4500, 'ram', '14/02/2012'),
(2,0,6500, 'radhe', '11/11/2014'),
(3,1,4500, 'gopal', '14/02/2015'),
(5,1,4500, 'gopala', '04/02/2015'),
(5,1,4500, 'gopala', '04/02/2015'),
(6,0,14500, 'gopal', '14/02/2015')
;
I have 3 conditions to filter the table:
No complete duplicate record
If record with same id but different Name and date field then add all of them to final result
If status=1 for any record then select that record of respective id
Add all record with id different from id of above 3 conditions
I have written this query:
SELECT * FROM Student1
GROUP BY id,status,amount,Name,date
HAVING COUNT(*) > 1
UNION
SELECT * FROM Student1 Student1
WHERE id IN
(
SELECT id FROM Student1
GROUP BY id
HAVING COUNT(DISTINCT name) > 1
AND COUNT(DISTINCT date) > 1
)
UNION
SELECT * FROM Student1 Student1
WHERE status=1 AND id IN
(
SELECT id FROM Student1
GROUP BY id
HAVING COUNT(id) >= 2
);
Result:
id status amount Name date
4 1 1500 ghanshyam 18/10/2015
1 1 4500 ram 14/02/2012
3 1 4500 gopal 14/02/2015
5 1 4500 gopala 04/02/2015
2 0 2000 shyam 05/09/2013
2 0 8000 radheshyam 15/11/2013
2 0 6500 radhe 11/11/2014
As you can see 1st Select avoid duplicate, 2nd Select record with same id having different Name, date, 3rd Select to get record with id=1. I am using UNION to avoid duplication in result.
Now I need to add 4th query to get the record id=6 which is not present in all the above condition.
Expected Result:
id status amount Name date
4 1 1500 ghanshyam 18/10/2015
1 1 4500 ram 14/02/2012
3 1 4500 gopal 14/02/2015
5 1 4500 gopala 04/02/2015
2 0 2000 shyam 05/09/2013
2 0 8000 radheshyam 15/11/2013
2 0 6500 radhe 11/11/2014
6 0 14500 gopal 14/02/2015
I need to solve the 4th query. Please help.
If the only condition you want to filter, is id = 6, it is enough to add just:
SELECT * FROM Student1 WHERE id=6;
Which is direct translation of your request into SQL. And full version will be:
SELECT * FROM Student1
GROUP BY id,status,amount,Name,date
HAVING COUNT(*) > 1
UNION
SELECT * FROM Student1 Student1
WHERE id IN
(
SELECT id FROM Student1
GROUP BY id
HAVING COUNT(DISTINCT name) > 1
AND COUNT(DISTINCT date) > 1
)
UNION
SELECT * FROM Student1 Student1
WHERE status=1 AND id IN
(
SELECT id FROM Student1
GROUP BY id
HAVING COUNT(id) >= 2
)
UNION
SELECT * FROM Student1 WHERE id=6;
Result is as requested but in different order. DEMO
However, if you would like to get all id which were not filtered with your coditions, but you don't know their values, I would use a VIEW:
CREATE VIEW Student2 AS
SELECT * FROM Student1
GROUP BY id,status,amount,Name,date
HAVING COUNT(*) > 1
UNION
SELECT * FROM Student1 Student1
WHERE id IN
(
SELECT id FROM Student1
GROUP BY id
HAVING COUNT(DISTINCT name) > 1
AND COUNT(DISTINCT date) > 1
)
UNION
SELECT * FROM Student1 Student1
WHERE status=1 AND id IN
(
SELECT id FROM Student1
GROUP BY id
HAVING COUNT(id) >= 2
);
And then query with it:
SELECT * FROM Student2
UNION
SELECT * FROM Student1 WHERE id NOT IN (SELECT id FROM Student2);
The result is the same. DEMO
Related
Let's say I have a table called activitiesthat has 2 columns: nameActivityand zipCode.
How do I write a query that returns all activities a for which there are no other activities b that:
have the same zipCode
that share the same nameActivity as another activity c. With other words, for this condition, we need to check that de nameActivity of activity b is unique.
Example:
nameActivity zipCode
kayaking 1000
bouldering 1000
museum 2000
paintball 2000
museum 3000
karting 4000
Following all the conditions above this should result in:
nameActivity zipCode
paintball 2000
museum 3000
karting 4000
For the first part of the condition :
SELECT (array_agg(nameActivity))[1]
, zipCode
FROM activities
GROUP BY zipCode
HAVING count(*) = 1
result :
array_agg zipcode
karting 4000
museum 3000
(paintball, 2000) is excluded from the result because another nameActivity (museum) exists for the same zipCode.
The second part of the condition is unclear : what means "b share the same nameActivity as another activity c" ???
well, this was a hard one. I think I got it right with some tinkering, hope it helps.
with data (nameActivity, zipCode)as (
Select 'kayaking', 1000 from dual union all
Select 'bouldering', 1000 from dual union all
Select 'museum', 2000 from dual union all
Select 'paintball', 2000 from dual union all
Select 'museum', 3000 from dual union all
Select 'karting', 4000 from dual )
,duplicatesname as(
select nameActivity,zipCode
from(
select d1.nameActivity,max(zipCode) zipCode, count(*) cnt
from data d1
group by d1.nameActivity)
where cnt >1)
,withoutduplicatename as(
select nameActivity,zipCode
from (
select d1.nameActivity,d1.zipCode,d2.nameActivity na2,d2.zipCode zi2
from data d1
left join duplicatesname d2 on d1.nameActivity = d2.nameActivity
and d1.zipCode != d2.zipCode
) where na2 is null)
,duplicatZipCode as(
select zipCode
from(
select zipCode , count(*) cnt
from withoutduplicatename d1
group by d1.zipCode)
where cnt >1)
select nameActivity,zipCode
from withoutduplicatename d1
where d1.zipCode not in (select zipCode from duplicatZipCode)
order by zipCode
I got near.
But kayaking can't be ignored.
create table activities (
nameActivity varchar(30),
zipCode int
)
insert into activities
(nameActivity, zipCode) values
('kayaking', 1000)
, ('bouldering', 1000)
, ('museum', 2000)
, ('paintball', 2000)
, ('museum', 3000)
, ('karting', 4000)
SELECT nameActivity, zipCode
FROM
(
SELECT nameActivity, zipCode
, ROW_NUMBER() OVER (PARTITION BY zipCode) rn
FROM activities a
WHERE NOT EXISTS (
select 1
from activities a2
group by a2.zipCode
having count(*) = 1
and a2.zipCode != a.zipCode
and max(a2.nameActivity) = a.nameActivity
)
) q
WHERE rn = 1
nameactivity | zipcode
:----------- | ------:
kayaking | 1000
paintball | 2000
museum | 3000
karting | 4000
db<>fiddle here
I have 3 tables
Table A:
Cid acc_id acc balance
1 345 100
1 456 300
2 347 500
Table B:
Cid acc_id acc balance
1 348 100
1 457 300
2 349 500
Table C:
Cid acc_id acc balance
1 340 100
1 457 300
2 344 500
I need to create a single table which gives the sum of balances for each customer across all 3 tables.
Cid. Balance
1. 1200
2. 1500
I need SQL for this purpose. Since customer id is repeating within the table I m confused.
Use union all and aggregation
select cid, sum(balance)
from ((select Cid, acc_id, balance
from a
) union all
(select Cid, acc_id, balance
from b
) union all
(select Cid, acc_id, balance
from c
)
) abc
group by cid;
You can use UNION ALL, as in:
select
cid,
sum(balance) as balance
from (
select * from table_a
union all
select * from table_b
union all
select * from table_c
) x
group by cid
I have a scenario to get the respective field value of "Max" and "Min" records
Please find the sample data below
-----------------------------------------------------------------------
ID Label ProcessedDate
-----------------------------------------------------------------------
1 Label1 11/01/2016
2 Label2 11/02/2016
3 Label3 11/03/2016
4 Label4 11/04/2016
5 Label5 11/05/2016
I have the "ID" field populated in another table as a foreign key. While querying those records in that table based on the "ID" field I need to get the "Label" field of "Max" Processed date and "Min" processed date.
-----------------------------------------------------------------------
ID LabelID GroupingField
-----------------------------------------------------------------------
1 1 101
2 2 101
3 3 101
4 4 101
5 5 101
6 1 102
7 2 102
8 3 102
9 4 102
And the final result set I expect it to look something like this.
-----------------------------------------------------------------------
GroupingField FirstProcessed LastProcessed
-----------------------------------------------------------------------
101 Label1 Label5
102 Label1 Label4
I have 'almost' managed to get this above result using rank function but still not satisfied with it. So I am looking if someone can provide me with a better option.
Thanks,
Prakazz
CREATE TABLE #Details (ID INT,LabelID INT,GroupingField INT)
CREATE TABLE #Details1 (ID INT,Label VARCHAR(100),ProcessedDate VARCHAR(100))
INSERT INTO #Details1 (ID ,Label ,ProcessedDate )
SELECT 1,'Label1','11/01/2016' UNION ALL
SELECT 2,'Label2','11/02/2016' UNION ALL
SELECT 3,'Label3','11/03/2016' UNION ALL
SELECT 4,'Label4','11/04/2016' UNION ALL
SELECT 5,'Label5','11/05/2016'
INSERT INTO #Details (ID ,LabelID ,GroupingField )
SELECT 1,1,101 UNION ALL
SELECT 2,2,101 UNION ALL
SELECT 3,3,101 UNION ALL
SELECT 4,4,101 UNION ALL
SELECT 5,5,101 UNION ALL
SELECT 6,1,102 UNION ALL
SELECT 7,2,102 UNION ALL
SELECT 8,3,102 UNION ALL
SELECT 9,4,102
;WITH CTE (GroupingField , MAXId ,MinId) AS
(
SELECT GroupingField,MAX(LabelID) MAXId,MIN(LabelID) MinId
FROM #Details
GROUP BY GroupingField
)
SELECT GroupingField ,B.Label FirstProcessed, A.Label LastProcessed
FROM CTE
JOIN #Details1 A ON MAXId = A.ID
JOIN #Details1 B ON MinId = B.ID
You can use SQL Row_Number() function using Partition By as follows with a combination of Group By
;with cte as (
select
t.Label, t.ProcessedDate,
g.GroupingField,
ROW_NUMBER() over (partition by GroupingField Order By ProcessedDate ASC) minD,
ROW_NUMBER() over (partition by GroupingField Order By ProcessedDate DESC) maxD
from tbl t
inner join GroupingFieldTbl g
on t.ID = g.LabelID
)
select GroupingField, max(FirstProcessed) FirstProcessed, max(LastProcessed) LastProcessed
from (
select
GroupingField,
FirstProcessed = CASE when minD = 1 then Label else null end,
LastProcessed = CASE when maxD = 1 then Label else null end
from cte
where
minD = 1 or maxD = 1
) t
group by GroupingField
order by GroupingField
I also used CTE expression to make coding easier and understandable
Output is as
I have following table with duplicate records.I want to retrieve record with duplicate id but different name,date.
CREATE TABLE Student1
(`id` int,`status` int,`amount` int , `Name` varchar(10), `date` varchar(55))
;
INSERT INTO Student1
(`id`,`status`,`amount`, `Name`, `date`)
VALUES
(1,0,4500, 'ram', '04/02/2012'),
(2,0,2000, 'shyam', '05/09/2013'),
(4,0,1500, 'ghanshyam', '08/11/2014'),
(3,0,4500, 'gopal', '04/02/2012'),
(2,0,8000, 'radheshyam', '15/11/2013'),
(4,1,1500, 'ghanshyam', '18/10/2015'),
(1,1,4500, 'ram', '14/02/2012'),
(2,0,6500, 'radhe', '11/11/2014'),
(3,1,4500, 'gopal', '14/02/2015')
;
Expected Result:
id status amount Name date
2 0 2000 shyam 05/09/2013
2 0 8000 radheshyam 15/11/2013
2 0 6500 radhe 11/11/2014
select * from Student1
where id in
(
select id from Student1
group by id
having count(distinct name) > 1
and count(distinct date) > 1
)
I have two result sets that look approximately like this:
Id Name Count
1 Asd 1
2 Sdf 4
3 Dfg 567
4 Fgh 23
But the Count column data is different for the second one and I would like both to be displayed, about like this:
Id Name Count from set 1 Count from set two
1 Asd 1 15
2 Sdf 4 840
3 Dfg 567 81
4 Fgh 23 9
How can I do this in SQL (with union if possible)?
My current SQL, hope this will better explain what I want to do:
(SELECT Id, Name, COUNT(*) FROM Customers where X)
union
(SELECT Id, Name, COUNT(*) FROM Customers where Y)
select *
from
(
SELECT 'S1' as dataset, Id, Name, COUNT(*) as resultcount FROM Customers where X
union
SELECT 'S2',Id, Name, COUNT(*) FROM Customers where Y
) s
pivot
(sum(resultcount) for dataset in (s1,s2)) p
You can do something like:
;WITH Unioned
AS
(
SELECT 'Set1' FromWhat, Id, Name FROM Table1
UNION ALL
SELECT 'Set2', Id, Name FROM Table2
)
SELECT
Id,
Name,
SUM(CASE FromWhat WHEN 'Set1' THEN 1 ELSE 0 END) 'Count from set 1',
SUM(CASE FromWhat WHEN 'Set2' THEN 1 ELSE 0 END) 'Count from set 2'
FROM Unioned
GROUP BY Id, Name;
SQL Fiddle Demo