My table has columns Name, EmpName, Date. For distinct Name and EmpName values, Date should be only one value per month
For example:
Name EmpName Date
-----------------------
abc emp1 3/19/2018
abc emp1 3/22/2018 (This record should be rejected)
xyz emp2 3/15/2018 valid record
I wrote something like this
SELECT
name, empname,
ROW_NUMBER() OVER (PARTITION BY YEAR(date), MONTH(date) ORDER BY date DESC)
I got stuck writing a CASE statement
You can use row_number() :
select top (1) with ties t.*
from table t
order by row_number() over (partition by name, empname, year(date), month(date) order by date);
However, based on sample data simple aggregation would also work :
select name, empname, min(date)
from table t
group by name, empname, year(date), month(date);
Related
I'm in Snowflake and am trying to mark the first occurrence of a unique ID in a column. I've been playing around with first_value but am not really getting anywhere.
So my data looks something like this:
ID Date
123 1/2019
123 2/2019
123 3/2019
234 2/2019
234 3/2019
And ideally I want something like this:
ID Date First?
123 1/2019 1
123 2/2019 0
123 3/2019 0
234 2/2019 1
234 3/2019 0
How do I accomplish this?
You want ROW_NUMBER:
SELECT
ID,
Date,
IFF(ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Date) = 1, 1, 0) AS First
FROM
schema.table
ORDER BY ID, Date
;
This checks whether the current row is the first date for the ID, and if it is, assigns a value of 1 (otherwise 0).
LAG can also be used to solve this..
SELECT id
,date
,lag(id) over (partition by id order by date) is null as first
FROM table_name;
Which can be also done with FIRST_VALUE like
SELECT id
,date
,first_value(id) over (partition by id order by date) = date as first
FROM table_name;
If your intention is to retrieve the first occurrence of a unique ID in a column then the row_number() or the dense_rank() function can help.
with cte as
(
select ID, Date,
row_number() over (partition by ID order by date) as row_number
from table1
)
select * from cte where row_number = 1;
with cte as
(
select ID, Date,
dense_rank() over (partition by ID order by date) as rank
from stack1
)
select * from cte where rank = 1;
I need a query to display employee names, dept no and highest salary in dept no wise
Example
ENAME SAL dept no
KING 5000 10
FORD 3000 20
SCOTT 3000 20
BLAKE 2850 30
As the commenter said, it's helpful when you provide more detail about what you've tried.
Nonetheless, I think you're looking for something like this:
;with cte as (
select ename, sal, [dept no]
, row_number() over (partition by [dept no] order by sal desc, ename) rn
from your_table
)
select *
from cte
where rn = 1
Note that your example data shows the same SAL of 3000 for [dept no] 20. To attempt to break ties, I added the ename to the order by statement.
This query displays correctly
select ENAME, SAL, [deptno]
from (
select *
, DENSE_RANK() over(partition by [deptno] order by sal desc) as Highest_sal
from Employee
) a
where a.Highest_sal = 1
I have some records coming from 4 tables and date is not the common field in all of them but I use 'as'. Now I need to order by date
select id,convert(varchar(20), SoldDate,3) as Date from sale
union
select id,convert(varchar(20), PaymentDate,3) as Date from purchase
union
select id,convert(varchar(20), PaymentClearedDate,3) as Date from payments
union
select id,convert(varchar(20), PaymentClearedDate,3) as Date from orders
order by Date desc
I need order by Date
You can use CTE or subquery :
SELECT t.*
FROM ( <Query>
) t
ORDER BY r.Date DESC;
However, i would argue on date conversations, if you want just date then use cast(SoldDate as date) & latter convert it to dd\MM\yy.
So, your updated query would be :
SELECT t.id, CONVERT(VARCHAR(10), t.[Date], 3) AS [Date]
FROM (SELECT id, CAST(SoldDate AS DATE) AS [Date]
FROM sale
UNION
SELECT id, CAST(PaymentDate AS DATE)
FROM purchase
UNION
. . .
) t
ORDER BY t.[Date] DESC;
What goes wrong with your code? You are ordering by Date there as far as I can see. If you want to order by the Dates in date order, create another column which is the date, as a date type, e.g.
select id,convert(varchar(20), SoldDate,3) as Date,SoldDate as d2 from sale
union
select id,convert(varchar(20), PaymentDate,3) as Date, PaymentDate as d2 from purchase
union
select id,convert(varchar(20), PaymentClearedDate,3) as Date, PaymentClearedDate as d2 from payments
union
select id,convert(varchar(20), PaymentClearedDate,3) as Date, PaymentClearedDate as d2 from orders
order by d2 desc
you might need to cast your dates to type date if they are stored in some other text format
e.g.
select id,convert(varchar(20), SoldDate,3) as Date,CAST(SoldDate as datetime2) as d2 from sale
union
...etc
order by d2 desc
I have a table that has families_id, date, metric_id
A record gets inserted for each families_id there will be a date & metric_id 1-10.
So there should be 10 records for each families_id, the records get inserted with a date an each should follow on from each other. So metric_id 10 date should be greater than metric_id 6 date.
On mass how can I select where they have
Missed a metric_id
The date for the metric_id 6 is before the date for metric_id 2
use row_number to assign an ordinal to the metric_id and date for each family, then they should match - also metric_id, 1,2,3,4... should match with its calculated row_number(), also 1,2,3,4....
SELECT IQ.* FROM (SELECT families_id, [date], metric_id,
ROW_NUMBER() OVER (PARTITION BY families_id ORDER BY [date]) rn_date,
ROW_NUMBER() OVER (PARTITION BY families_id ORDER BY metricid) rn_metric FROM YourTable) IQ
WHERE IQ.rn_date != IQ.rn_metric;
--should detect wrongly ordered metric_ids
SELECT IQ.* FROM (SELECT families_id, [date], metric_id,
ROW_NUMBER() OVER (PARTITION BY families_id ORDER BY [date]) rn_date,
ROW_NUMBER() OVER (PARTITION BY families_id ORDER BY metricid) rn_metric FROM YourTable) IQ
WHERE IQ.metric_id != IQ.rn_metric;
Another possibility - detect a metricID where the date is earlier for a higher id
SELECT y1.families_id, y1.metric_id FROM yourtable y1
WHERE
EXISTS(SELECT 0 FROM yourtable y2 WHERE y1.families_id = y2.families_id
AND
y2.date < y1.date
AND
y2.metricid > y1.metricid)
I am having problems reading code like
SELECT
employeeID as ID,
RANK() OVER (ORDER BY AVG (Salary) DESC) AS Value
FROM Salaries
which supposedly gets the average salary of every employees
My understanding is the code should be
SELECT
employeeID as ID,
RANK() OVER (Partition By employeeID ORDER BY AVG (Salary) DESC) AS Value
FROM Salaries
but the above code works just fine?
First one is not working for me (returning Msg 8120
Column 'Salaries.employeeID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause), until I add group by employeeID:
SELECT
employeeID as ID,
RANK() OVER (ORDER BY AVG (Salary) DESC) AS Value
FROM Salaries
GROUP BY employeeID
Perhaps, for better understanding, it can be rewritten equivalently as:
;with cte as (
SELECT employeeID, AVG (Salary) as AvgSalary
FROM Salaries
GROUP BY employeeID
)
select employeeID as ID
, RANK() OVER (ORDER BY AvgSalary DESC) as Value
--, AvgSalary
from cte
In this case, average salary by employee is calculated in the CTE, and then query is extended with ranking column Value. Adding partition by employeeID to over clause:
;with cte as (
SELECT employeeID, AVG (Salary) as AvgSalary
FROM Salaries
GROUP BY employeeID
)
select employeeID as ID
, RANK() OVER (partition by employeeID ORDER BY AvgSalary DESC) as Value
--, AvgSalary
from cte
will lead to Value = 1 for every row in the result set (which is not what seem attempted to be achieved), because of rank() will reset numbering to 1 for each distinct employeeID, and employeeID is distinct in every row, since data was aggregated by this column prior to ranking.