Retrieve all distinct records from table and if any changes happen between two similar distinct record then need to consider both. Using select query - sql

I want to convert table1 into table2. As I need to find out all distinct records excluding mis_date fro the table and most important condition is if any changes happen between two similar distinct records than in that case I want both of them as two distinct records.
Example:
i/p
empId Empname Pancard MisDate
123 alex ads234 31/11/2012
123 alex ads234 31/12/2012
123 alex ads234 31/01/2013
123 alex dds124 29/02/2013
123 alex ads234 31/03/2013
123 alex ads234 31/04/2013
123 alex dds124 30/05/2013
Expected o/p
empId Empname Pancard MisDate
123 alex ads234 31/11/2012
123 alex dds124 29/02/2013
123 alex ads234 31/03/2013
123 alex dds124 30/05/2013

Assuming there's only one row for each MisDate (otherwise you'll have to find another way to specify ordering):
SELECT t1.empId, t1.Empname, t1.Pancard
FROM Table1 t1
LEFT OUTER JOIN Table1 t2
ON t2.MisDate = (SELECT MAX(MisDate) FROM Table1 t3 WHERE t3.MisDate < t1.MisDate)
WHERE t2.empId IS NULL
OR t2.empId <> t1.empId OR t2.Empname <> t1.Empname OR t2.Pancard <> t1.Pancard
SQL Fiddle example
This performs a self-join on the previous record, as ordered by MisDate, outputting if it is different or if there is no previous record (it is the first row).
Note: You've got some funky dates. I assume these are just transcription errors and have corrected them in the fiddle.

Related

SQL Join on Like Operator

I know this question has been asked a couple of times and i've tried to use the solution for my problem. Unfortunately it did not get me the output i wanted. I need to update ID column in one table by joining it to another table where the joining column does not have exact value.
TableA TableB
EmpNo EmpName ID EmpNo EmpName ID TermDate
101 John Doe Null 250termed_101 John Doe 250 11-15-2018
102 Jane Doe Null 251termed_102 Jane Doe 251 02-25-2019
101 Bryan Adams Null 252termed_101 Bryan Adams 252 03-12-2020
Here's what i tried but was unable to get the required output because the below query is giving me duplicates:
select *
from TableA as A left join
TableB as B
on B.EmpNo like '%' + A.EmpNo + '%' and A.EmpNo is not null
Output Required:
EmpNo EmpName ID
101 John Doe 250
102 Jane Doe 251
101 Bryan Adams 252
I need to populate ID column from TableB into TableA by joining these 2 tables on EmpNo. For the first record, John Doe is terminated on 11-15-2018 and his employee number is assigned to Bryan Adams with unique ID. I need to populate the ID column from TableB into Table A for the corresponding employee who had that number at the time.
Thanks in advance
If your problem is truly that you're getting duplicates that you don't want, you can throw a DISTINCT in. But your problem is in the data: Bryan Adams and John Doe both have employee numbers of 101, so they look duplicated when you join to TableB.
This SQL Fiddle might help you: http://sqlfiddle.com/#!18/f30476/10
You seem on the right path, the update statement should look like the following, also notice how I am making the like comparison more accurate:
update A SET
ID = B.ID
from
TableA as A
left join TableB as B on
B.EmpNo like '%_' + A.EmpNo and
A.EmpNo is not null;
that will break when you have 101 and 1101 or 2101, so it's not a good match, so let's revisit:
update A SET
ID = B.ID
from
TableA as A
inner join TableB as B on
RIGHT(B.EmpNo, len(B.EmpNo) - charindex('_', B.EmpNo)) = A.EmpNo
A.EmpNo is not null and --you don't need this,
charindex('_', B.EmpNo) > 0;--needed, otherwise you get string errors

PostgreSQL: How to join two tables using between date?

I really don't know how to ask this question of mine.
I'll illustrate it using two tables I needed to join.
TABLE_1
Name Date
John 01-01-2016
May 04-08-2015
Rose 10-25-2016
Mary 12-15-2015
Ruby 07-07-2017
TABLE_2
Signatory DateFrom DateTo
President 1 01-01-2015 12-31-2015
President 2 01-01-2016 12-31-2016
RESULT:
Name Date Signatory
John 01-01-2016 President 2
May 04-08-2015 President 1
Rose 10-25-2016 President 2
Mary 12-15-2015 President 1
Ruby 07-07-2017 NULL
All I need to check if the Date of Table_1 is within the DateFrom and DateTo of Table_2 to get the Signatory field.
How I can do that?
Thanks a lot! ^_^
Try this:
SELECT t1.*, t2.Signatory
FROM Table_1 AS t1
LEFT JOIN Table_2 AS t2
ON t1."Date" BETWEEN t2.DateFrom AND t2.DateTo
What you need is just a LEFT JOIN with BETWEEN in the ON clause in order to determine whether Date field of Table_1 falls within any [DateFrom, DateTo] interval of Table_2.
Demo here

Aggregate operation oracle

I have two tables and I need to find the person with the highest value.
TABLE1
NAME ID
--------------- ---------------
MIKE 101
MIKE 102
BETTY 103
BETTY 104
BETTY 105
TIM 106
TABLE2
ID VALUE
-------- --------------
101 12
102 10
103 20
104 20
105 10
106 5
I can write a select statement that will give a result of name and values:
SELECT name, value
FROM table1, table2
WHERE table1.id = table.id;
NAME VALUE
----- ----------
MIKE 12
MIKE 10
BETTY 20
BETTY 20
BETTY 10
TIM 5
Now I need to aggregate the values of the rows with equal names and I can not figure it out. Am I going about it the correct way?
Please try this :
select a.name,max(b.value) as value
from table1 a
inner join table2 b on a.id = b.id
group by a.name
Anyway, you tagged mysql and oracle in the question. Luckily, this sql works in both. But you have to remove one of these two tags, to make sure which dbms are you use.
Use this.. and since your column names are unique, you don't need any alias.
select name, max(value) as MaxValue
from table1
inner join table2 on table1.id = table2.id
group by name

SQL Query, GROUP/COUNT issue with INNER JOIN

I've got a data set composed primarily of dates, IDs, and addresses, that looks a bit like this:
datadate id address
20150801 Bob 123
20150801 Bob 123
20150801 Dan 345
20150801 Dan 456
20150801 Dan 567
20150801 George 234
20150801 Jim 123
20150801 Jim 123
20150801 John 678
20150801 John 123
20150802 Tom 123
20150802 Tom 234
20150802 Tom 345
My goal is to write a query which identifies any IDs which are associated with multiple distinct addresses for a specific date (or date range). I want the query results to give me the name and distinct addresses. So, for this data set, the results I'd like to see would look like this, for date 8/1/2015:
datadate id address
20150801 Dan 345
20150801 Dan 456
20150801 Dan 567
20150801 John 678
20150801 John 123
The query I've worked up so far is this, but it's not really working for me:
SELECT a.[datadate], a.[id], a.[address], b.[count1]
FROM table1 AS a INNER JOIN (SELECT [id], COUNT([address]) as [count1] FROM table1 GROUP BY [id] having count1 > 1 ) AS b ON a.[id]=b.[id]
WHERE a.[datadate] = '20150801'
ORDER BY a.[id], a.[address];
Any suggestions?
Just modifying your existing query a little bit, you can change your having to count(distinct address) and then joining back to the table to get your address values like this:
SELECT t.datadate
,t.id
,t1.address
FROM (
SELECT datadate
,id
,count(DISTINCT address) address
FROM test
WHERE datadate = '20150801'
GROUP BY datadate,id
HAVING count(DISTINCT address) > 1
) t
INNER JOIN test t1 ON t.datadate = t1.datadate
AND t.id = t1.id;
I tested this on SQL Server, but should be similar in MS-Access as well.
SQL Fiddle Demo
Edit
I just read your question again and it appears you want all duplicates. In which case I would use exists to see if another row with the same id but a different address exists.
select * from mytable t1
where datadate = '20150801'
and exists (
select 1 from mytable t2
where t2.id = t1.id
and t2.address <> t1.address
and t2.datadate = t1.datadate
)

SQL Join Ignore multiple matches (fuzzy results ok)

I don't even know what the name of my problem is called, so I'm just gonna put some sample data. I don't mind fuzzy results on this (this is the best way I can think to express it. I don't mind if I overlook some data, this is for approximated evaluation, not for detailed accounting, if that makes sense). But I do need every record in TABLE 1, and I would like to avoid the nulls case indicated below.
IS THIS POSSIBLE?
TABLE 1
acctnum sub fname lname phone
12345 1 john doe xxx-xxx-xxxx
12346 0 jane doe xxx-xxx-xxxx
12347 0 rob roy xxx-xxx-xxxx
12348 0 paul smith xxx-xxx-xxxx
TABLE 2
acctnum sub division
12345 1 EAST
12345 2 WEST
12345 3 NORTH
12346 1 TOP
12346 2 BOTTOM
12347 2 BALLOON
12348 1 NORTH
So if we do a "regular outer" join, we'd get some results like this, since the sub 0's don't match the second table:
TABLE AFTER JOIN
acctnum sub fname lname phone division
12345 1 john doe xxx-xxx-xxxx EAST
12346 0 jane doe xxx-xxx-xxxx null
12347 0 rob roy xxx-xxx-xxxx null
12348 0 paul smith xxx-xxx-xxxx null
But I would rather get
TABLE AFTER JOIN
acctnum sub fname lname phone division
12345 1 john doe xxx-xxx-xxxx EAST
12346 0 jane doe xxx-xxx-xxxx TOP
12347 0 rob roy xxx-xxx-xxxx BALLOON
12348 0 paul smith xxx-xxx-xxxx NORTH
And I'm trying to avoid:
TABLE AFTER JOIN
acctnum sub fname lname phone division
12345 1 john doe xxx-xxx-xxxx EAST
12345 1 john doe xxx-xxx-xxxx WEST
12345 1 john doe xxx-xxx-xxxx NORTH
12346 0 jane doe xxx-xxx-xxxx TOP
12346 0 jane doe xxx-xxx-xxxx BOTTOM
12347 0 rob roy xxx-xxx-xxxx BALOON
12348 0 paul smith xxx-xxx-xxxx NORTH
So I decided to go with using a union and two if conditions. I'll accept a null for conditions where the sub account is defined in table 1 but not in table 2, and for everything else, I'll just match against the min.
If I'm understanding correctly, it looks like you're trying to join on the sub column if it matches. If there's no match on sub, then you want it to select the "first" row for that acctnum. Is this correct?
If so, you'll need to left join on the full match, then perform another left join on a select statement that determines the division that corresponds to the lowest sub value for that acctnum. The row_number() function can help you with this, like this:
select
t1.acctnum,
t1.sub,
t1.fname,
t1.lname,
t1.phone,
isnull(t2_match.division, t2_first.division) as division
from table1 t1
left join table2 t2_match on t2_match.acctnum = t1.acctnum and t2_match.sub = t1.sub
left join
(
select
acctnum,
sub,
division,
row_number() over (partition by acctnum order by sub) as rownum
from table2
) t2_first on t2_first.acctnum = t1.acctnum
EDIT
If you don't care at all about which record you get back from table 2 when a matching sub doesn't exist, you could combine two different queries (one that matches the sub and one that just takes the min or max division) with a union.
select
t1.acctnum,
t1.sub,
t1.fname,
t1.lname,
t1.phone,
t2.division
from table1 t1
join table2 t2 on t2.acctnum = t1.acctnum and t2.sub = t1.sub
union
select
t1.acctnum,
t1.sub,
t1.fname,
t1.lname,
t1.phone,
min(t2.division)
from table1 t1
join table2 t2 on t2.acctnum = t1.acctnum
left join table2 t2_match on t2_match.acctnum = t1.acctnum and t2_match.sub = t1.sub
where t2_match.acctnum is null
Personally, I don't find the union syntax any more compelling and you now have to maintain the query in two places. For this reason, I'd favor the row_number() approach.
try to use
SELECT MIN(Table_1.acctnum) as acctnum , MIN(Table_1.sub) as sub,MIN( Table_1.fname) as fname, MIN(Table_1.lname) as name, MIN(Table_1.phone) as phone, MIN(Table_2.division) as division
FROM Table_1 INNER JOIN Table_2 ON Table_1.acctnum = Table_2.acctnum AND Table_1.sub = Table_2.sub
where Table_1.sub>0
group by Table_1.acctnum
union
SELECT MIN(Table_1.acctnum) as acctnum , MIN(Table_1.sub) as sub,MIN( Table_1.fname) as fname, MIN(Table_1.lname) as name, MIN(Table_1.phone) as phone, MIN(Table_2.division) as division
FROM Table_1 INNER JOIN Table_2 ON Table_1.acctnum = Table_2.acctnum
where Table_1.sub=0
group by Table_1.acctnum
this is the result
12345 1 john doe xxxxxxxxxx EAST
12346 0 jane doe xxxxxxxxxx BOTTOM
12347 0 rob roy xxxxxxxxxx BALLOON
12348 0 paul smith xxxxxxxxxx NORTH
if you change min to max TOP will be insted of BOTTOM on the second row
It may also work for you:
SELECT t1.acctnum, t1.sub, t1.fname, t1.lname, t1.phone,
ISNULL(MAX(t2.division),MAX(t3.division)) as division
FROM table_1 t1
LEFT JOIN table_2 t2 ON (t2.acctnum = t1.acctnum AND t1.sub = t2.sub)
LEFT JOIN table_2 t3 ON (t3.acctnum = t1.acctnum)
GROUP BY t1.acctnum, t1.sub, t1.fname, t1.lname, t1.phone
This will give your desired result, exactly (for the shown data):
Updated to not assume there is always a sub==1 value:
SELECT
T1.acctnum,
T1.sub,
T1.fname,
T1.lname,
T1.phone,
T2.division
FROM
TABLE_1 T1
LEFT JOIN
TABLE_2 T2 ON T1.acctnum = T2.acctnum
AND
T2.sub = (SELECT MIN(T3.sub) FROM TABLE_2 T3 WHERE T1.acctnum = T3.acctnum)
ORDER BY
T1.lname,
T1.fname,
T1.acctnum