Since i'm new to Oracle SQL i'm in need of help.
I wish to create a new employee table in my database - fetching data from my raw table and basing the new data on 'date'.
EXAMPLE:
One of my employees have changed last name and i wish to create my table with his/hers latest data entry.
table1_raw with
columns pnbr; fname; lname; date
197001014688 ;Eva ;Andersson ;20150501
197001014688 ;Eva ;Sandsten ;20160501
198401011133 ;Peter ;Larsson ;20150102
198401011133 ;Peter ;Larsson ;20160102
194408011237 ;Sven ;Hansson ;20130203
table2 with
columns pnbr; fname; lname; date
197001014688 ;Eva ;Sandsten ;20160501
198401011133 ;Peter ;Larsson ;20160102
194408011237 ;Sven ;Hansson ;20130203
In SQL Server i've used the following query, with Common Table Expressions:
;WITH CTE as
(SELECT RN = ROW_NUMBER() OVER (PARTITION BY pnbr ORDER BY date DESC),
pnbr,
fname,
lname
FROM table1_raw)
SELECT
fname,
lname,
pnbr
INTO
table2
FROM
CTE
WHERE
RN = 1
How do i write this query in Oracle SQL?
Is there a more efficient/easier way to do this?
In Oracle your query will look like this -
insert into table2
select t.pnbr, t.fname, t.lname, t.date
from table1 t
inner join (
select pnbr, max(date) as MaxDate
from table1 tm
group by username
) tm on t.username = tm.username
and t.date = tm.MaxDate
To create a table based on a SELECT you need to use create table as in Oracle (and standard SQL)
Using rn = ... to define a column alias is invalid (standard) SQL as well, you need to use ... AS rn
And finally, the ; goes to the end of the statement, not in front of the with keyword:
create table table2
as
WITH CTE as (
SELECT ROW_NUMBER() OVER (PARTITION BY pnbr ORDER BY date DESC) as rn,
pnbr,
fname,
lname
FROM table1_raw
)
SELECT fname,
lname,
pnbr
FROM cte
WHERE rn = 1;
Related
I have a table that Tracks Employees and the days they have spent in a policy. I don't generate this Data, it is dumped to our Server Daily.
The table looks like this:
My Goal is to get rid of the duplicates by keeping only the most recent Date.
In this example, if I run the query, I would like it to keep Rows 11 for Nicholas Morris and 14 for Tiana Sullivan.
Assumption: First name and Last Name combo are unique
So far,
This is what I have been doing:
select *
from
Employees IN(
Select ID
from Employees
group by FirstName, lastName
Having count(*) > 1)
This returns to me the rows that have duplicates and I have to manually search them and remove the ones I don't want to keep.
I am sure there is a better way of doing this
Thanks for your help
You can use a CTE and ROW_NUMBER() function to do it.
The query to get the data is:
SELECT ID, FirstName, LastName, ROW_NUMBER()
OVER (PARTITION BY FirstName, LastName ORDER BY DaysInPolicy DESC) AS Identifier
FROM
Employees
The query to remove duplicates is:
;WITH CTE AS (
SELECT ID, ROW_NUMBER()
OVER (PARTITION BY FirstName, LastName ORDER BY DaysInPolicy DESC) AS Identifier
FROM
Employees
)
DELETE E
FROM
Employees E
INNER JOIN CTE C ON C.ID = E.ID
WHERE
C.Identifier > 1
You could delete using an exists operator where you remove any row that has the same first and last name, but with a newer date:
DELETE FROM employees e1
WHERE EXISTS (SELECT *
FROM employees e2
WHERE e1.FirstName = e2.FirstName AND
e1.LastName = e2.LastName AND
e1.DaysInPolicy < e2.DaysInPolicy)
Try this:
SELECT * FROM
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY Last_Name, First_Nmae ORDER BY DaysInPolicy DESC) AS RowNum
FROM Employees
) AS Emp
WHERE Emp.RowNum > 1
I have table contain multiple records for the name and DT, I need a query to check the Name don't have any new record in past 2 days based on the DT, how to create
Name DT
ABC 2017-09-17 06:02:23.000
ACD 2017-09-15 06:02:23.000
I think You need something like this:
SELECT Name,dt
from
(SELECT Name,MAX(dt) dt
FROM your_table
GROUP BY NAME) a
where dt < GETDATE()-2
Without knowing your table schema or sample data this is a wild guess at a query, but what you want should be doable with the GETDATE() function. If you want to use UTC time you can also use the GETUTCDATE() function.
Edit: Updated to include the ROW_NUMBER() function.
Edit 2: Replaced the GETDATE() where clause with a CTE to exclude names that have dt within the last 2 days.
WITH CTE AS (
SELECT
name
FROM table
WHERE dt > GETDATE()-2
)
SELECT
name,
dt
FROM (
SELECT
name,
dt,
ROW_NUMBER() OVER (PARTITION BY name ORDER BY dt desc) AS rn
FROM table
LEFT JOIN CTE ON
table.name = CTE.name
WHERE CTE.name IS NULL
) tbl
WHERE rn = 1
BEGIN TRAN
CREATE TABLE #CM (Name NVARCHAR(06), DT DATETIME)
INSERT INTO #CM
SELECT 'ABC','2017-09-17 06:02:23.000' UNION ALL
SELECT 'ACD','2017-09-15 06:02:23.000'
SELECT * FROM #CM
WHERE CONVERT(NVARCHAR(105),dt) < CONVERT(NVARCHAR(105),GETDATE()-2)
ROLLBACK TRAN
I want to get unique rows based on FirstName,EmailID. I tried few things by adding DISTINCT to all row that still get duplicate rows. tried Group By that failed with error. I can do a subquery but that will be slow. WHat is the best solution for below query
SELECT FirstName,LastName,FamilyName, EmailID,Phone,City,Country,CreatedOn,t.Type , ID
FROM Forms C JOIN Form_Type T
ON c.Form_TypeID = t.Form_TypeID
WHERE c.Form_TypeID = 1 AND DATEDIFF( "d", CreatedOn, GETDATE()) < 31
ORDER BY CreatedOn DESC
See if this works for you:
SELECT *
FROM (
SELECT FirstName,LastName,FamilyName, EmailID,Phone,City,Country,CreatedOn,t.Type , ID,
ROW_NUMBER() OVER (PARTITION BY FirstName ,EmailID ORDER BY CreatedOn DESC ) NewCol
FROM Forms C
JOIN Form_Type T ON c.Form_TypeID = t.Form_TypeID
WHERE c.Form_TypeID = 1
AND DATEDIFF("d", CreatedOn, GETDATE()) < 31
) t
WHERE NewCol = 1
I have added an extra column (i.e. NewCol) in the inner table. I am assuming that you wanted to display recent record (using CREATEDON) for each combination of "FirstName, Email"
DISTINCT will not work in your case, as you want all the fields from the table. So you need to use a sub-query to create a list of distinct names/emails.
You should be able to adapt the following example to your needs:
SELECT User, EMail, Address1, Address2
FROM Table1 t1
INNER JOIN (SELECT DISTINCT(User, EMail) FROM Table1) tmp ON t1.User = tmp.User AND t1.EMail = tmp.EMail
Using an INNER JOIN this returns only rows from Table1 that are in table tmp. Table tmp is defined as the distinct combinations of User and EMail from Table1.
So what happens is: You create a distinct list of User and EMail from Table1. Then you select all the entries from Table1 where User and EMail are in that list.
I have a table like so:
Id, Comment, LastUpdatedDate
I'm tyring to select the latest comment for that id. The table can have many comments on that id with different dates but I'm trying to get the latest date out of there. I've tried the following with no success:
SELECT tt.*
FROM tagtestresultcomment tt
INNER JOIN
(
SELECT tag_id, MAX(last_update) AS MaxDateTime
FROM tagtestresultcomment
GROUP BY tag_id
) groupedtt ON tt.tag_id = groupedtt.tag_id AND tt.last_update = groupedtt.MaxDateTime
order by tag_id
Does anyone have any ideas of how to achieve this?
Thanks!
It sounds like you want only the latest comment for each tag_id? In which case, here is one approach you can use from SQL 2005 and on:
;WITH CTE AS
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY tag_id ORDER BY last_update DESC) AS RowNo
FROM TagTestResultComment
)
SELECT * FROM CTE WHERE RowNo = 1
try this
Select * from tagtestresultcomment where last_update in
(select max(last_update) from tagtestresultcomment group by tag_id)
your query code is too redundant. first
tt.tag_id = groupedtt.tag_id AND tt.last_update = groupedtt.MaxDateTime
it's enough just
tt.tag_id = groupedtt.tag_id
and second, it's enough just
SELECT [desired field list extcept last_update and ],
tag_id,
MAX(last_update) AS MaxDateTime
FROM
tagtestresultcomment
group by
tag_id, [desired field list extcept last_update and tag_id]
at all to achieve your objective
I have tried something like this:
declare #tagtestresultcomment table
(
id int
, comment varchar(50)
,LastUpdatedDate datetime
)
--==== Populate table
insert into #tagtestresultcomment(id,comment,LastUpdatedDate)
select 1,'My name is Arthur','2011-06-09 00:00:00' union all
select 2,'My name is DW','2011-06-19 00:00:00' union all
select 2,'Arthur is my brother','2011-06-21 00:00:00' union all
select 1,'I have a sister named DW','2011-06-21 00:00:00' union all
select 3,'I am Muffy','2011-06-14 00:00:00' union all
select 3,'I like sports','2011-06-14 00:00:00'
-- SELECT stmt
select * from #tagtestresultcomment t
join
(
select id, MAX(lastupdateddate) as LastUpdatedDate from #tagtestresultcomment group by id
) m
on t.id = m.id
and t.LastUpdatedDate = m.LastUpdatedDate
The "MAX" group function wasn't working for me, so I used a sub-query. I had trouble wrapping my head around your single table example, so I'm using a common parent-child 1-to-many relationship with a blog and comment tables as an example.
SELECT
b.id,
b.content,
c.id,
c.blog_id,
c.content,
c.last_update
FROM blog b
INNER JOIN blog_comment c
ON b.id = c.blog_id AND c.id = (
SELECT TOP 1 id FROM blog_comment WHERE blog_id = b.id ORDER BY last_update DESC
)
The query takes a hit on my sub-query, as it will call that "SELECT TOP 1" query for each record in the blog table. I'd like to hear of a faster, more efficient example if possible.
I want to update row data where the row_number of the column (p_id) is 1.. but this syntax is providing error:
update app1
set p_id = 1
where Row_Number() = 1 over(p_id)
You can't use ROW_NUMBER() directly - you need to e.g. use a CTE (Common Table Expression) for that:
;WITH DataToUpdate AS
(
SELECT
SomeID,
p_id,
ROW_NUMBER() OVER(ORDER BY .......) AS 'RowNum'
FROM
dbo.app1
)
UPDATE DataToUpdate
SET p_id = 1
WHERE
RowNum = 1
In order to use the ROW_NUMBER function, you also need at least an ORDER BY clause to define an order by which the rows are ordered.
From your question, it's not very clear what criteria (column) you want to order by to determine your ROW_NUMBER(), and it's also not clear what kind of column there is to uniquely identify a row (so that the UPDATE can be applied)
This will update only the first employee of that age. May be used as a lottery type logic
create table emp(name varchar(3),Age int, Salary int, IncentiveFlag bit)
insert into emp values('aaa',23,90000,0);
insert into emp values('bbb',22,50000,0);
insert into emp values('ccc',63,60000,0);
insert into emp values('ddd',53,50000,0);
insert into emp values('eee',23,80000,0);
insert into emp values('fff',53,50000,0);
insert into emp values('ggg',53,50000,0);
update A
set IncentiveFlag=1
from
(
Select row_number() over (partition by Age order by age ) AS SrNo,* from emp
)A
where A.SrNo=1
TO Delete duplicates ;WITH CTE(Name,Address1,Phone,RN)
AS
(
SELECT Name,Address1,Phone,
ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Name) AS RN
)
DELETE FROM CTE WHERE RN > 1