SQL Rank based on date - sql

I am trying to link a customer to a "peferred" merchant based on number of visits within the last 18 months, with the tiebreaker being the most recent visit date. I'm having a bit of trouble with the tiebreaker. If there are two records both ranked 1 based on # of visits for a certain MemberID, I want to set the IsFirst bit column to 1 on the record with the MAX(EncounterDate) for that MemberID. How should I go about doing this?

This may help you... This is Oracle query based on existing emp table. I think it is a good idea to create structures when you posting a problem.
Replace first select with update etc...: UPDATE your table SET your date = max_date (max_hire_date in my example) WHERE your_field IN (select max date as in my example) AND rnk = 1 and rno = 1
SELECT * FROM
(
SELECT deptno
, ename
, sal
, RANK() OVER (PARTITION BY deptno ORDER BY sal desc) rnk
, ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY sal desc) rno
, MAX(hiredate) OVER (PARTITION BY deptno ORDER BY deptno) max_hire_date
FROM emp_test
WHERE deptno = 20
ORDER BY deptno
)
WHERE rnk = 1
--AND rno = 1 -- or 2 or any other number...
/
SQL>
DEPTNO ENAME SAL RNK RNO HIREDATE MAX_HIRE_DATE
-----------------------------------------------------------
20 SCOTT 3000 1 1 1/28/2013 1/28/2013
20 FORD 3000 1 2 12/3/1981 1/28/2013

The following SQL gets the information you want, assuming the structure of certain tables:
select c.*, NumVisits, MaxVisitDate, MaxFirstVisitDate
(select count(*)
from visits v
where v.customerid = c.customerid and
v.visi
from customers c join
(select customerid,
sum(case when visitdate between getdate() - 365*1.5 and getdate()
then 1 else 0
end) as NumVisits,
max(visitdate) as MaxVisitDate,
max(case when IsFirst = 1 then visitdate end) as MaxFirstVisitDate
from visits
group by customerid
) v
on c.customerid = v.customerid
From this information, you can put together the logic for what you want to do. When MaxVisitDate = MaxFirstVisitDate, then the bit is set on the most recent date.
The answer to your update question is something like this:
update visits
set IsFirst = 1
where exists (select max(encounterDate)
from visits v2
where v2.customer_id = visits.customer_id
having max(encounterDate) = visits.encounterDate)
)

Related

How to sort the row of record and update dynamically in SQL?

Clarification on SQL query syntax : we have an Employee table which has two columns Emp Id and EmpName and its values looks like this:
100, a
200, b
300, c
I have to update the EmpName for 100 with "Joe", 200 with "John", 300 with "Sam". These same 3 names then need to repeat in order for the rest of the table.
How to pick EmpId in ascending order sequence and update the EmpName accordingly?
WITH cteRowNums AS (
SELECT EmpId,
EmpName,
ROW_NUMBER() OVER(ORDER BY EmpId) AS RowNum
FROM Employee
)
UPDATE cteRowNums
SET EmpName = CASE WHEN RowNum % 3 = 1 THEN 'Joe'
WHEN RowNum % 3 = 2 THEN 'John'
WHEN RowNum % 3 = 0 THEN 'Sam'
END;
Hi please add a row_num column
after that update using ROW_NUMBER()
something like
Alter table emp1 add row_num varchar(10)
with cte as (
select id,name,row_num,ROW_NUMBER() over (order by [id]) as rn
from emp1
)
update cte set row_num = 'Test'+ convert(varchar,rn)
row_number this will create a ordered column regarding [Emp Id].
and run update statement to get desired result.

Pivoting in sql [duplicate]

This question already has answers here:
SQL Server: Examples of PIVOTing String data
(7 answers)
Closed 7 years ago.
i have sql table with data as given below
emp id empname dept
------- ---- ------
1 a Hr
2 b Hr
3 c Tech
4 d Hr
5 e Admin
7 f Tech
8 g Admin
Now i want to pivot the above table get the result like this
Hr Tech Admin
----- ----- -----
Empname a c e
Empname b f g
Empname d
I am just wondering is this even possible using pivoting in sql or there is any other mean to achieve this
You can use conditional aggregation with ROW_NUMBER:
SQL Fiddle
WITH Cte AS(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY dept ORDER BY empid)
FROM tbl
)
SELECT
[Hr] = MAX(CASE WHEN dept = 'Hr' THEN empname END),
[Tech] = MAX(CASE WHEN dept = 'Tech' THEN empname END),
[Admin] = MAX(CASE WHEN dept = 'Admin' THEN empname END)
FROM cte
GROUP BY rn
Here is the PIVOT version:
SQL Fiddle
;WITH Cte AS(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY dept ORDER BY empid)
FROM tbl
)
SELECT *
FROM(
SELECT
dept, MAX(empname) AS empname,RN
FROM Cte
GROUP BY dept, RN
)t
PIVOT
(
MAX(empname)
FOR dept in ([Hr], [Tech], [Admin])
)piv
This type of manipulation is often best done in the presentation layer. It appears that you want three different lists in the columns, so the rows are not really related to each other.
That said, you can do this in SQL, but you need to get a "list position" for each column. For that, use row_number():
select h.empname as hr, t.empname as tech, a.empname as admin
from (select empname, row_number() over (order by empname) as seqnum
from table
where dept = 'Hr'
) h full outer join
(select empname, row_number() over (order by empname) as seqnum
from table
where dept = 'Tech'
) t
on t.seqnum = h.seqnum full outer join
(select empname, row_number() over (order by empname) as seqnum
from table
where dept = 'Admin'
) a
on a.seqnum in (h.seqnum, t.seqnum)

oracle display customer who purchased most cars WITHOUT analytic functions

I'm currently trying to answer the following question:
Display the name of the customer who has purchased the most cars from Archie’s Luxury Motors.
Tables I'm working with:
Customer
(custID, name, DOB, streetAddress, suburb, postcode,
gender, phoneNo, email, type)
SalesTransaction
(VIN, custID, agentID, dateOfSale, agreedPrice)
My query
select *
from (
select customer.name
from customer, salestransaction
where customer.custID = salestransaction.custID
group by (customer.name), salestransaction.custID
order by count(*) desc
)
where rownum=1;
Now I've found out that I cannot use analytic functions (rownum & rank)
How would I go about doing this with using pure transactional SQL only?
You could use MAX and COUNT aggregate functions:
WITH data AS
(SELECT c.name cust_nm,
COUNT(*) cnt
FROM customer c,
salestransaction s
WHERE c.custID = s.custID
GROUP BY c.NAME
ORDER BY cnt DESC
)
SELECT cust_nm FROM data WHERE cnt =
(SELECT MAX(cnt) FROM DATA
);
An example from EMP and DEPT table:
SQL> WITH data AS
2 (SELECT e.deptno,
3 COUNT(*) cnt
4 FROM emp e,
5 dept d
6 WHERE e.deptno = d.deptno
7 GROUP BY e.deptno
8 ORDER BY cnt DESC
9 )
10 SELECT deptno FROM DATA WHERE cnt =
11 (SELECT MAX(cnt) FROM DATA
12 );
DEPTNO
----------
30
SQL>

Finding department having maximum number of employee

I have a table employee
id name dept
1 bucky shp
2 name shp
3 other mrk
How can i get the name of the department(s) having maximum number of employees ? ..
I need result
dept
--------
shp
SELECT cnt,deptno FROM (
SELECT rank() OVER (ORDER BY cnt desc) AS rnk,cnt,deptno from
(SELECT COUNT(*) cnt, DEPTNO FROM EMP
GROUP BY deptno))
WHERE rnk = 1;
Assuming you are using SQL Server and each record representing an employee. So you can use window function to get the result
WITH C AS (
SELECT RANK() OVER (ORDER BY dept) Rnk
,name
,dept
FROM table
)
SELECT TOP 1 dept FROM
(SELECT COUNT(Rnk) cnt, dept FROM C GROUP BY dept) t
ORDER BY cnt DESC
With common table expressions, count the number of rows per department, then find the biggest count, then use that to select the biggest department.
WITH depts(dept, size) AS (
SELECT dept, COUNT(*) FROM employee GROUP BY dept
), biggest(size) AS (
SELECT MAX(size) FROM depts
)
SELECT dept FROM depts, biggest WHERE depts.size = biggest.size
Based on one of the answer, Let me try to explain step by step
First of all we need to get the employee count department wise. So the firstly innermost query will run
select count(*) cnt, deptno from scott.emp group by deptno
This will give result as
Now out of this we have to get the one which is having max. employee i.e. department 30.
Also please note there are chances that 2 departments have same number of employees
The second level of query is
select rank() over (order by cnt desc) as rnk,cnt,deptno from
(
select count(*) cnt, deptno from scott.emp group by deptno
)
Now we have assigned ranking to each department
Now to select rank 1 out of it. we have a simplest outer query
select * from
(
select rank() over (order by cnt desc) as rnk,cnt,deptno from
(
select count(*) cnt, deptno from scott.emp group by deptno
)
)
where rnk=1
So we have the final result where we got the department which has the maximum employees. If we want the minimum one we have to include the department table as there are chances there is a department which has no employees which will not get listed in this table
You can ignore the scott in scott.emp as that is the table owner.
The above SQL can be practised at Practise SQL online

Selecting the second row of a table using rownum

I have tried the below query:
select empno from (
select empno
from emp
order by sal desc
)
where rownum = 2
This is not returning any records.
When I tried this query
select rownum,empno from (
select empno from emp order by sal desc)
It gives me this output:
ROWNUM EMPNO
1 7802
2 7809
3 7813
4 7823
Can anyone tell me what's the problem with my first query? Why is it not returning any records when I add the ROWNUM filter?
To explain this behaviour, we need to understand how Oracle processes
ROWNUM. When assigning ROWNUM to a row, Oracle starts at 1 and
only increments the value when a row is selected; that is, when all
conditions in the WHERE clause are met. Since our condition requires
that ROWNUM is greater than 2, no rows are selected and ROWNUM is
never incremented beyond 1.
The bottom line is that conditions such as the following will work as
expected.
.. WHERE rownum = 1;
.. WHERE rownum <= 10;
While queries with these conditions will always return zero rows.
.. WHERE rownum = 2;
.. WHERE rownum > 10;
Quoted from Understanding Oracle rownum
You should modify you query in this way in order to work:
select empno
from
(
select empno, rownum as rn
from (
select empno
from emp
order by sal desc
)
)
where rn=2;
EDIT: I've corrected the query to get the rownum after the order by sal desc
In the first query, the first row will have ROWNUM = 1 so will be rejected. The second row will also have ROWNUM = 1 (because the row before was rejected) and also be rejected, the third row will also have ROWNUM = 1 (because all rows before it were rejected) and also be rejected etc... The net result is that all rows are rejected.
The second query should not return the result you got. It should correctly assign ROWNUM after ORDER BY.
As a consequence of all this, you need to use not 2 but 3 levels of subqueries, like this:
SELECT EMPNO, SAL FROM ( -- Make sure row is not rejected before next ROWNUM can be assigned.
SELECT EMPNO, SAL, ROWNUM R FROM ( -- Make sure ROWNUM is assigned after ORDER BY.
SELECT EMPNO, SAL
FROM EMP
ORDER BY SAL DESC
)
)
WHERE R = 2
The result:
EMPNO SAL
---------------------- ----------------------
3 7813
try this:
SELECT ROW_NUMBER() OVER (ORDER BY empno) AS RowNum,
empno
FROM tableName
WHERE RowNumber = 2;
Snippet From Source:
SELECT last_name FROM
(SELECT last_name, ROW_NUMBER() OVER (ORDER BY last_name) R FROM employees)
WHERE R BETWEEN 51 and 100
REFERENCE
For nth row using rownum in oracle:
select * from TEST WHERE ROWNUM<=n
MINUS
select * from TEST WHERE ROWNUM<=(n-1);
Example for second row :
select * from TEST WHERE ROWNUM<=2
MINUS
select * from TEST WHERE ROWNUM<=1;
Select * From (SELECT *,
ROW_NUMBER() OVER(ORDER BY column_name DESC) AS mRow
FROM table_name
WHERE condition) as TT
Where TT.mRow=2;
Select Second Row From a Table in Oracle
SELECT *
FROM (SELECT * FROM emp ORDER BY rownum DESC)
WHERE rownum=1
try this way it's working 100%
SQL> SELECT * FROM STUD;
RNUMBER SNAME MARKS
104 mahesh 85
101 DHANU 20
102 BHARATH 10
100 RAJ 50
103 GOPI 65
SQL> select * from(select MARKS,ROWNUM AS RS from ( select * from stud order by marks desc)) where RS=2;
MARKS RS
65 2
SQL>
select empno
from
(
select empno,rownum as rum
from emp,
order by sal desc
)
where rum=2;
You can use RANK or DENSE_RANK to achieve what you are trying to achieve here.
Try this query 100% working
Select * from(select rownum as rn,emp.* from emp) Where rn=2;