Lost on creating a query for this scenario - sql-server-2008

Here is a simplified version of the table structure.
Employee
(
ID GUID NOT NULL
OldID GUID NULL
Name VARCHAR(50) NOT NULL
CreationDate DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
)
It contains employee information as well as any changes been made to employee attributes. This way we can get a complete audit of changes been made. When OldID is NULL, that basically mean the latest data. Here is an example, I am using integer values for identifier to make this example easier to understand.
ID OldId Name CreationDate
13 NULL John 15-July-2013
12 13 John1 14-July-2013
11 12 John2 13-July-2013
10 11 John3 12-July-2013
121 NULL Smith 15-July-2013
To start with I can get the unique employees from table by
SELECT ID, Name FROM Employee WHERE OldId IS NULL
I am looking to get latest ID but its earliest name. So that result should be two rows
ID Name
13 John3
121 Smith
I am not sure how can I get these results. Any help will be highly appreciated.

Here's one approach that works for your data:
with groups as
(
select groupID = ID, *
from Employee
where OldID is null
union all
select g.groupID, e.*
from groups g
inner join Employee e on g.ID = e.OldID
)
, ranks as
(
select *
, firstRank = row_number () over (partition by groupID order by creationDate)
from groups
)
select ID = groupID
, Name
from ranks
where firstRank = 1
SQL Fiddle with demo.

Related

MySQL join tables and show values excluding specific user_id

Details:
MySQL tables
create table request (
id int not null primary key auto_increment,
date_requested timestamp,
user_id int
);
create table verify (
id int not null primary key auto_increment,
user_id int,
request_id int,
created timestamp
);
Values
Request Table
ID DATE REQUESTED USER ID
1 2020.. 1
2 2020.. 3
Verify Table
ID USER_ID REQUEST_ID CREATED
1 2 1 2020...
Problem:
I have this query below:
select * from request join verify on request.id = verify.request_id where verify.user_id !=2;
This returns me nothing. Why is it not showing the 2nd record from request table?
My goal is simply return all values from request tables based on this:
If record.id is in verify table then check if verify table has user_id of 2
If it does, then do not show that request record
If there are no record.id in verify table at all
Then show them
You need a left join of the tables and filter out the matching rows:
select r.*
from request r left join verify v
on r.id = v.request_id and v.user_id =2
where v.request_id is null
See the demo.
Or with NOT EXISTS:
select r.*
from request r
where not exists (
select 1 from verify v
where r.id = v.request_id and v.user_id =2
)
See the demo.
Results:
| id | date_requested | user_id |
| --- | ------------------- | ------- |
| 2 | 2020-04-08 00:00:00 | 3 |

Reduce mysql database to elminiate duplicates

I have a table called "lane" with the following properties.
CREATE TABLE `lane` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`origRegion` varchar(45) NOT NULL,
`origState` char(2) NOT NULL,
`destRegion` varchar(45) NOT NULL,
`destState` char(2) NOT NULL
PRIMARY KEY (`id`)
)
There are duplicate rows in this table of the following columns: origState, origRegion, destState, destRegion. I'd like to be able to select all rows JOINED to what the min(id) is of the first occurance.
For example, with data:
1 ALL MA ALL OH
2 ALL MA ALL OH
3 ALL MA ALL OH
and a SQL similar to this (which misses all the duplicate rows):
select l.*, l2.count, l2.minId from tmpLane l
JOIN (SELECT id, min(ID) as minId from tmpLane
GROUP BY origRegion, origState, destRegion, destState) l2 on l.id = l2.id;
Result (note the count and minId at the end):
1 ALL MA ALL OH 3 1
2 ALL MA ALL OH 3 1
3 ALL MA ALL OH 3 1
Note, that the query used above is an adaptation of the solution here (which doesn't work in this situation)
SELECT ID,
origRegion,
origState,
destRegion,
destState,
(SELECT COUNT(*)
FROM Lane l3
WHERE l.origRegion = l3.origRegion
and l.origState = l3.origState
and l.destRegion = l3.destRegion
and l.destState = l3.destState) as 'Count',
(SELEcT MIN(ID)
FROM Lane l2
WHERE l.origRegion = l2.origRegion
and l.origState = l2.origState
and l.destRegion = l2.destRegion
and l.destState = l2.destState) as minID
FROM lane l
You can run this query to remove all the duplicate rows from your database:-
ALTER IGNORE TABLE `lane`
ADD UNIQUE INDEX (`origRegion`, `origState`, `destRegion`, `destState`);
This will add unique index to your table and remove all dulicate rows and will make sure that no duplicate rows being inserted in future.

MySQL return min value but not null

I have a table where there are columns students and grade obtained(A-F). A student can appear for test more than once. Sometimes students register but do not appear for test so the grade is not entered but student record entry is made.
I want to get best grade of each student. When I do min(grade) if there is any record with null, null gets selected instead of 'A-F' which indicate proper results. I want to get min of grade if grade exists or null if there are no grades.
SELECT `name`,min(grade) FROM `scores` group by `name`
Id | Name | Grade
1 | 1 | B
2 | 1 |
3 | 1 | A
4 | 2 | C
5 | 2 | D
For name 1 it is fetching second record not the third one having 'A'.
As per the conversations in the comments, the easiest solution may be to convert your empty strings to null, and let the builtin min function do the heavy lifting:
ALTER TABLE scores MODIFY grade VARCHAR(1) NULL;
UPDATE scores
SET grade = null
WHERE grade = '';
SELECT name, MIN(grade)
FROM scores
GROUP BY name
If this is not possible, a dirty trick you could use is to have a case expression convert the empty string to a something you know will come after F:
SELECT name,
MIN(CASE grade WHEN '' THEN 'DID NOT PARTICIPATE' ELSE grade END)
FROM scores
GROUP BY name
And if you really need the empty string back, you can have another case expression around the min:
SELECT name, CASE best_grade WHEN 'HHH' THEN '' ELSE best_grade END
FROM (SELECT name,
MIN(CASE grade WHEN '' THEN 'HHH' ELSE grade END) AS
best_grade
FROM scores
GROUP BY name) t
Change your query slightly to -
SELECT `name`,min(grade) FROM `scores` WHERE grade <> "" group by `name`
If the name has a grade/s assigned to it then the lowest will be returned else the resultset will be null

how to create virtual table for inserting null value in mysql

employee
id name
1 mark
2 Clark
3 Johnson
4 peter
emp_salary
empid sal
1 2000
2 4000
2 null
4 6000
5 null
I need employee name whose salary is null...and also i need show 5000 salary where salary is null, without inserting value in emp_salary table
I tried
Select e.name,e.empid,e.salary
from table employee e inner join emp_salary em on e.id=em.empid
where em.salary=null
but this query is not working
I need to select null value and show 5000 on null value without affecting table
Select e.name,e.empid,'5000' salary
from table employee e inner join emp_salary em on e.id=em.empid
where em.salary is null
check for null with "IS NULL" not "=NULL"
This will show all employees whose salary is null, but your select will show the "salary" as 5000

MySQL merge amounts in a 2 rows

I'm looking to create a sql statement that will update a large set of data.
What I have is a table like
id, transid, amount, narative1, narative 2, total, active
1 1234 23.2 NULL NULL NULL 1
2 1234 120.33 NULL NULL NULL 1
3 1235 98.00 NULL NULL NULL 1
When there are two rows with the same transid I need to total them put the result in the total column of the first one with that transid and put the second amount in naritive2 of the first instance as well as make the second one inactive. It should ignore single rows for a transid.
The result of what I want to do should be:
id, transid, amount, narative1, narative 2, total, active
1 1234 23.2 NULL 120.33 143.53 1
2 1234 120.33 NULL NULL NULL 0
3 1235 98.00 NULL NULL NULL 1
I know a bit of a thong twister but..
Ideally I'd like to do this in just a MySQL statements. So I don't mind having to do multiple sql statements but I want to avoid connecting it to PHP etc. Its a very large set of data.
This will update only those transactions that have exactly 2 rows (not 1 and not 3 or more).
UPDATE mytable mtu
JOIN (
SELECT minid, maxid, mtmin.amount AS minamt, mtmax.amount AS maxamt
FROM (
SELECT MIN(id) AS minid, MAX(id) AS maxid
FROM mytable mti
GROUP BY
transid
HAVING COUNT(*) = 2
) mt
JOIN mytable mtmin
ON mtmin.id = minid
JOIN mytable mtmax
ON mtmax.id = maxid
) mts
ON id IN (minid, maxid)
SET narative2 = CASE id WHEN minid THEN minamt ELSE NULL END,
total = CASE id WHEN minid THEN minamt + maxamt ELSE NULL END,
active = (id = minid)