Select MAX, but want to show the other columns - sql-server

Oke, I have this data:
INSERT INTO JobHistory(EmployeeID, EffDate, EffSeq, EmploymentStatus,
JobTitle, Salary, ActionDesc)
VALUES
(1000,'07-31-2008',1,'A','Intern',2000,'New Hire'),
(1000,'05-31-2009',1,'A','Production Technician',2000,'Title Change'),
(1000,'05-31-2009',2,'A','Production Technician',2500,'Salary Change'),
(1000,'11-01-2009',1,'A','Production Technician',3000,'Salary Change'),
(1200,'01-10-2009',1,'A','Design Engineer',5000,'New Hire'),
(1200,'05-01-2009',1,'T','Design Engineer',5000,'Termination'),
(1100,'08-01-2008',1,'A','Accounts Payable Specialist I',2500,'New Hire'),
(1100,'05-03-2009',1,'A','Accounts Payable Specialist II',2500,'Title Change'),
(1100,'05-01-2009',2,'A','Accounts Payable Specialist II',3000,'Salary Change');
and if I do this:
SELECT MAX(EffDate) as MaxDate--, EmployeeID, JobTitle
FROM JobHistory
you will get the MAX EffData(11-01-2009). ok. But now you will see only the column: EffData. But I also want to show the EmployeeID and JobTitle for that only returned record. But you can't do that, because you have to use then GROUP BY. And than you will return more records
ANd with a CTE it is also not possible.
So how to return just one record(the max of Effdata) but also shown the EmployeeID and jobtitle?
Thank you

You need TOP 1 with Order by not Max aggregate
SELECT Top 1 EffDate as MaxDate, EmployeeID, JobTitle
FROM JobHistory
Order by MaxDate desc
In case there is a Tie in max EffDate then and you want to see the Tie records then use TOP 1 with Ties
SELECT Top 1 with Ties EffDate as MaxDate, EmployeeID, JobTitle
FROM JobHistory
Order by MaxDate desc

Related

Oracle INSERT when selecting from multiple tables

What's wrong with this query? My insert needs to get data from other tables, but when I use select, it gives me error.
Here is the query:
INSERT INTO PAYMENT (
OWNER_HI,
ACCOUNT_ID,
DATE_PAYMENT,
ACCOUNT_VALUE_BEFORE,
CURRENCY,EXCHANGE_RATE,
SUM,
SUM_USD,
DATE_INPUT,
OPERATOR_ID,
DOCUMENT,
INVOICE_ID)
VALUES (
OWNER,
ID,
TODAY,
SALDO,
CURRENCY,
RATE,
50,
(50 * RATE),
TODAY,
386,
'teste sis',
null)
(SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD') "NOW" FROM DUAL) TODAY
(SELECT VALUE FROM ACCOUNT WHERE ACCOUNT_ID = 386) SALDO
(SELECT CURRENCY_IDCURRENCY_ID FROM CURRENCY_EXCHANGE WHERE rownum=1 ORDER BY CURRENCY_ID DESC) CURRENCY
(SELECT EXCHANGE_RATE FROM CURRENCY_EXCHANGE WHERE rownum=1 ORDER BY CURRENCY_ID DESC) RATE;
And this is the erro:
Erro de SQL: ORA-00933: SQL command not properly ended
00933. 00000 - "SQL command not properly ended"
Perhaps what you meant was something more like
INSERT INTO PAYMENT (
OWNER_HI,
ACCOUNT_ID,
DATE_PAYMENT,
ACCOUNT_VALUE_BEFORE,
CURRENCY,EXCHANGE_RATE,
SUM,
SUM_USD,
DATE_INPUT,
OPERATOR_ID,
DOCUMENT,
INVOICE_ID)
VALUES (
OWNER,
ID,
TO_CHAR(SYSDATE, 'YYYY-MM-DD'),
(SELECT VALUE FROM ACCOUNT WHERE ACCOUNT_ID = 386),
(SELECT CURRENCY_IDCURRENCY_ID FROM CURRENCY_EXCHANGE WHERE rownum=1 ORDER BY CURRENCY_ID DESC),
(SELECT EXCHANGE_RATE FROM CURRENCY_EXCHANGE WHERE rownum=1 ORDER BY CURRENCY_ID DESC),
50,
(50 * RATE),
TODAY,
386,
'teste sis',
null);
Best of luck.
We cannot mix INSERT ... VALUES and INSERT ... SELECT syntax. Choose one or the other. As you need values from other tables, you need INSERT ... SELECT.
There is no relationship between the tables you are querying so use a CROSS JOIN. This won't create a problem as long as you select only one row from each.
SELECT EXCHANGE_RATE FROM CURRENCY_EXCHANGE WHERE rownum=1 ORDER BY CURRENCY_ID DESC doesn't do what you think it does, because ROWNUM is allocated before the sort not afterwards. To get the toppermost currency, use an analytic function like ROW_NUMBER() in a sub-query and filter on that.
I've had to make a couple of guesses because you aren't clear about all the business rules you are implementing but you need something like this:
INSERT INTO PAYMENT (
OWNER_HI,
ACCOUNT_ID,
DATE_PAYMENT,
ACCOUNT_VALUE_BEFORE,
CURRENCY,EXCHANGE_RATE,
SUM,
SUM_USD,
DATE_INPUT,
OPERATOR_ID,
DOCUMENT,
INVOICE_ID)
select user, -- where does OWNER come from??
saldo.account_id,
trunc(sysdate),
SALDO.value,
CURRENCY.CURRENCY_ID ,
CURRENCY.EXCHANGE_RATE ,
50,
(50 * CURRENCY.EXCHANGE_RATE ),
trunc(sysdate),
386,
'teste sis',
null
from ( select CURRENCY_ID,
EXCHANGE_RATE,
row_number() over (order by CURRENCY_ID DESC ) as rn
FROM CURRENCY_EXCHANGE ) currency
cross join
(SELECT * FROM ACCOUNT WHERE ACCOUNT_ID = 386) SALDO
where currency.rn = 1
Note: I've ignored your casting of sysdate to a string (as "TODAY") because storing dates as strings is such incredibly bad practice. I'm hoping you're just doing it as a wait of stripping away the time element from sysdate, which we can also achieve with truncation.

SQL Server Group rows with multiple occurences of Group BY columns

I am trying to summarize a dataset and get the minimum and maximum date for each group. However, a group can exist multiple times if there is a gap. Here is sample data:
CREATE TABLE temp (
id int,
FIRSTNAME nvarchar(50),
LASTNAME nvarchar(50),
STARTDATE datetime2(7),
ENDDATE datetime2(7)
)
INSERT into temp values(1,'JOHN','SMITH','2013-04-02','2013-05-31')
INSERT into temp values(2,'JOHN','SMITH','2013-05-31','2013-10-31')
INSERT into temp values(3,'JANE','DOE','2013-10-31','2016-07-19')
INSERT into temp values(4,'JANE','DOE','2016-07-19','2016-08-11')
INSERT into temp values(5,'JOHN','SMITH','2016-08-11','2017-02-01')
INSERT into temp values(6,'JOHN','SMITH','2017-02-01','9999-12-31')
I am looking to summarize the data as follows:
JOHN SMITH 2013-04-02 2013-10-31
JANE DOE 2013-10-31 2016-08-11
JOHN SMITH 2016-08-11 9999-12-31
A "group by" will combine the two John Smith records together with the incorrect min and max dates.
Any help is appreciated.
Thanks.
As JNevill pointed out, this is a classic Gaps and Islands problem. Below is one solution using Row_Number().
Select FirstName
,LastName
,StartDate=min(StartDate)
,EndDate =max(EndDate)
From (
Select *
,Grp = Row_Number() over (Order by ID) - Row_Number() over (Partition By FirstName,LastName Order by EndDate)
From Temp
) A
Group By FirstName,LastName,Grp
Order By min(StartDate)
Please try the following...
SELECT firstName,
lastName,
MIN( startDate ) AS earliestStartDate,
MAX( endDate ) AS latestEndDate
FROM temp
GROUP BY firstName,
lastName;
This statement will use the GROUP BY statement to group together the records based on firstName and lastName combinations. It will then return the firstName and lastName for each group as well as the earliest startDate for that group courtesy of the MIN() function and the latest endDate for that group courtesy of the MAX() function.
If you have any questions or comments, then please feel free to post a Comment accordingly.

get first row for each group

I want to transform this data
account; docdate; docnum
17700; 9/11/2015; 1
17700; 9/12/2015; 2
70070; 9/1/2015; 4
70070; 9/2/2015; 6
70070; 9/3/2015; 9
into this
account; docdate; docnum
17700; 9/12/2015; 2
70070; 9/3/2015; 9
.. for each account I want to have one row with the most current (=max(docdate)) docdate. I already tried different approaches with cross apply and row_number but couldn't achieve the desired results
Use ROW_NUMBER:
SELCT account, docdate, docnum
FROM (
SELECT account, docdate, docnum,
ROW_NUMBER() OVER (PARTITION BY account
ORDER BY docdate DESC) AS rn
FROM mytable ) AS t
WHERE t.rn = 1
PARTITION BY account clause creates slices of rows sharing the same account value. ORDER BY docdate DESC places the record having the maximum docdate value at the top of its related slice. Hence rn = 1 points to the record with the maximum docdate value within each account partition.

SQL MULTIPLE JOIN-LEFT OUTER JOIN [Find Values between date range]

I have 4 tables to use JOIN query in MSSQL
1. Sales: ItemID, AreaCode, IndID,Cost
2. Ind: AreaCode, IndID, Insite,InLocation
3. ItemPrice: ItemID, AreaID, IndID, ActicationDate, Price
4. Invoice: ItemID, IndID, AreaId, InvoiceDate
I want to get IndID and AreaCode from table 1 on basis of that I want to find records from Ind table and from those records look for Insite and AreaCode with InLocation=’ ’ from same table.
From that records get IndID .
Using that IndID and ItemID, find that Price for that particular Item from ItemPrice Table. The price for that particular item is from the activationDate is applicable to specific invoice on basis of date.
I.e. If Activation Date is 1st Jan and Price is $5 -->And Invoice date is 2nd then Price is $5. But if next day ActivationDate is 2nd Jan and Price is updated to $7. and Invoice is created on 3rd Jan the price should be $7.
I.e.
Getting this:
Looking for something like below
SELECT DISTINCT sl.AreaCode,sl.IndID,sl.cost,
id.IndID, id.AreaCode, id.InLocation, id.InSite,
id2.IndID, id2.AreaCode, id2.InLocation, id2.InSite,
ip.ItemId,ip.price,ip.ActivationDate,
iv.InvoiceDate
from Sales s
LEFT OUTER JOIN Ind id
ON s.IndID= id.IndID
AND s.AreaCode=id.AreaCode
LEFT OUTER JOIN Ind id2
ON id.AreaCode=id2.AreaCode
AND id.IndID=id2.IndID
AND id.InSite=id2.InSite
AND id.InLocation = ''
LEFT OUTER JOIN ItemPrice ip
ON s.ItemId=ip.ItemId
AND id2.AreaCode=ip.AreaCode
AND id2.IndID=ip.IndID
LEFT OUTER JOIN Invoice iv
ON s.ItemId=iv.ItemId
AND iv.InvoiceDate >= ip.ActivationDate
Finally cracked.
select *,
(select top 1 price
from itemPrice
where itemPrice.ActivationDate <= t.InvoiceDate
order by itemPrice.ActivationDate desc) as Price
from Invoice t
Here s result

SQL query to count non unique field

I'm trying to figure out how to add a count on the email field in the query on the end but the problem I have is some of the data required is unique i.e. ID, DateTime but the email is not which I want a count of. I just can't figure it out how to do it in one SQL line.
e.g. Return:-
101, bla, prd, test#test.com, alfred, comp, test, 2015-10-10 10:10:10, 2 <-- count
100, bla, prd, test#test.com, alfred, comp, test, 2015-09-10 10:11:10, 2
099, bla, prd, anoter#email.com, simpson, comp, test, 2014-10-10 10:10:10, 1
098, bla, prd, bla#email.com, henry, comp, test, 2014-05-10 10:10:10, 1
Query
select TOP 200
ID,
FromPage,
Product,
Email,
Name,
Company,
Industry,
DateTime,
(count code here as EmailTotal)
from InstallEmails
WHERE product like 'prd%'
ORDER BY ID DESC
If you are using SQL Server 2005 or later, you can use a window function
SELECT TOP 200
ID,
FromPage,
Product,
Email,
Name,
Company,
Industry,
DateTime,
EmailTotal = COUNT(*) OVER(PARTITION BY Email)
FROM InstallEmails
WHERE product like 'prd%'
ORDER BY ID DESC;
For earlier versions, you will need to use a subquery:
SELECT TOP 200
ID,
FromPage,
Product,
Email,
Name,
Company,
Industry,
DateTime,
EmailTotal = ( SELECT COUNT(*)
FROM ( SELECT TOP 200 Email
FROM InstallEmails
WHERE product like 'prd%'
ORDER BY id DESC
) AS ie2
WHERE ie2.Email = ie.Email
)
FROM InstallEmails AS ie
WHERE product like 'prd%'
ORDER BY ID DESC;
worked it out.. appears to be ok.
select TOP 200 *, (select COUNT(email) from InstallEmails where email = t.email) as EmailTotal
from InstallEmails as t
where product like 'prd%'
ORDER BY ID DESC

Resources