Select Only min and max value per group - sql

How to select only 1 of min and max value of tap_time = tap_type 1(min) and 0(max) heres my unfinished query! Hope someone can help me.
use RFIDEmployee_DB
select *
from (
select FK_student_ID, Tap_Type, FK_Terminal_ID, Student_No, Last_Name, First_Name, Middle_Name, Tap_Time
from tbGateEntry
inner join tbStudentInfo on tbGateEntry.FK_student_ID = tbStudentInfo.ID
) t
order by Last_Name , Tap_Time

Rank function could help you choose first 1 by each type, change column name based on your requirement
use RFIDEmployee_DB
select *
from (
select FK_student_ID, Tap_Type, FK_Terminal_ID, Student_No, Last_Name, First_Name, Middle_Name, Tap_Time, ROW_NUMBER() OVER (PARTITION BY Tap_Type ORDER BY Tap_Time) R
from tbGateEntry
inner join tbStudentInfo on tbGateEntry.FK_student_ID = tbStudentInfo.ID
) t
where R = 1
order by Last_Name , Tap_Time

Related

SQL query to compare multiple columns in same table in oracle

I have a requirement to find emplid having data difference in same table. Table consist of 50-60 columns.. I need to check if any column has change in data from previous row, emplidshould get pick up as well as if any new employee get add that also needs to pick up..
I have created a basic query and it is working but need some way to achieve same purpose as I do not want to write every column name.
My query:
select
emplid
from
ps_custom_tbl t, ps_custom_tbl prev_t
where
prev_t.emplid = t.emplid
and t.effdt = (select max effdt from ps_custom_tbl t2
where t2.emplid = t.emplid)
and prev_t.effdt = (select max(effdt) from ps_custom_tbl prev_t2
where emplid = prev_t.emplid and effdt < t.effdt)
and (t.first_name prev_t.first_name Or t.last_name prev_t.last_name …. 50 columns);
Can you please suggest another way to achieve same thing?
You can use MINUS.
if no_data then both are the same, if there are some records - mean that there is a difference between
create table emp as select * from hr.employees;
insert into emp select employee_id+1000, first_name, last_name, email, phone_number, hire_date, job_id, salary, commission_pct, manager_id,
decode(department_id ,30,70, department_id)
from hr.employees;
select first_name, last_name, email, phone_number, hire_date, job_id, salary, commission_pct, manager_id, department_id
from emp where employee_id <= 1000
minus
select first_name, last_name, email, phone_number, hire_date, job_id, salary, commission_pct, manager_id, department_id
from emp where employee_id > 1000;
But you have to list all columns, because if you have eg different dates or ids - they will be compared too. But it's easier to list columns in SELECT clause then write for everyone WHERE condition.
Maybe it will help.
-- or if different tables and want to compare all cols simply do
drop table emp;
create table emp as select * from hr.employees;
create table emp2 as
select employee_id, first_name, last_name, email, phone_number, hire_date, job_id, salary, commission_pct, manager_id,
decode(department_id ,30,70, department_id) department_id
from hr.employees;
select * from emp
minus
select * from emp2;
---- ADD DATE CRITERIA
-- yes, you can add date criteria and using analytical functions check which
-- is newer and which is
older and then compare one to another. like below:
drop table emp;
create table emp as select * from hr.employees;
insert into emp
select
employee_id,
first_name,
last_name,
email,
phone_number,
hire_date+1,
job_id,
salary,
commission_pct,
manager_id,
decode(department_id ,30,70, department_id)
from hr.employees;
with data as --- thanks to WITH you retrieve data only once
(select employee_id, first_name, last_name, email, phone_number,
hire_date,
row_number() over(partition by employee_id order by hire_date desc) rn -- distinguish newer and older record,
job_id, salary, commission_pct, manager_id, department_id
from emp)
select employee_id, first_name, last_name, email, phone_number, department_id from data where rn = 1
MIUNUS--- find the differences
select employee_id, first_name, last_name, email, phone_number, department_id from data where rn = 2;
You will have to write all columns in some sense no matter what you do.
In terms of comparing current and previous, you might find this easier
select
col1,
col2,
...
lag(col1) over ( partition by empid order by effdt ) as prev_col1,
lag(col2) over ( partition by empid order by effdt ) as prev_col2
...
and then you comparison will be along the lines of
select *
from ( <query above >
where
decode(col1,prev_col1,0,1) = 1 or
decode(col2,prev_col2,0,1) = 1 or
...
The use of DECODE in this way handles the issues of nulls.
My requirement is to send out data to managers, they change any/all/none of the data in the columns, and send back to me. I then have to identify each column that has a difference from what I sent, and mark those columns as changed for a central office reviewer to visually scan and approve/deny the changes for integration back into the central data set.
This solution may not fit your needs of course, but a template structure is offered here that you can augment to meet your needs no matter the number of columns. In the case of your question, 50-60 columns will make this SQL query huge, but I've written heinously long queries in the past with great success. Add columns a few at a time rather than all wholesale according to this template and see if they work along the way.
You could easily write pl/sql to write this query for you for the tables in question.
This would get very cumbersome if you had to compare columns from 3 or more tables or bi-directional changes. I only care about single direction changes. Did the person change my original row columns or not. If so, what columns did they change, and what was my before value and what is their after value, and show me nothing else please.
In other words, only show me rows with columns that have changes with their before values and nothing else.
create table thing1 (id number, firstname varchar2(10), lastname varchar2(10));
create table thing2 (id number, firstname varchar2(10), lastname varchar2(10));
insert into thing1 values (1,'Buddy', 'Slacker');
insert into thing2 values (1,'Buddy', 'Slacker');
insert into thing1 values (2,'Mary', 'Slacker');
insert into thing2 values (2,'Mary', 'Slacke');
insert into thing1 values (3,'Timmy', 'Slacker');
insert into thing2 values (3,'Timm', 'Slacker');
insert into thing1 values (4,'Missy', 'Slacker');
insert into thing2 values (4,'Missy', 'Slacker');
commit;
Un-comment commented select * queries one at a time after each data set to understand what is in each data set at each stage of the refinement process.
with rowdifferences as
(
select
id
,firstname
,lastname
from thing2
minus
select
id
,firstname
,lastname
from thing1
)
--select * from rowdifferences
,thing1matches as
(
select
t1.id
,t1.firstname
,t1.lastname
from thing1 t1
join rowdifferences rd on t1.id = rd.id
)
--select * from thing1matches
, col1differences as
(
select
id
,firstname
from rowdifferences
minus
select
id
,firstname
from thing1matches
)
--select * from col1differences
, col2differences as
(
select
id
,lastname
from rowdifferences
minus
select
id
,lastname
from thing1matches
)
--select * from col2differences
,truedifferences as
(
select
case when c1.id is not null then c1.id
when c2.id is not null then c2.id
end id
,c1.firstname
,c2.lastname
from col1differences c1
full join col2differences c2 on c1.id = c2.id
)
--select * from truedifferences
select
t1m.id
,case when td.firstname is not null then t1m.firstname end beforefirstname
,td.firstname afterfirstname
,case when td.lastname is not null then t1m.lastname end beforelastname
,td.lastname afterlastname
from thing1matches t1m
join truedifferences td on t1m.id = td.id
;

select max sum of user from table, as user with maximum amount?

I have a table as
create table mock_sales
(
first_name character varying,
last_name character varying,
amount integer
);
insert into mock_sales(first_name, last_name, amount)
values('ted','mosby', 100),
('lily', 'aldrin', 400),
('ted', 'mosby', 350),
('barney', 'Stinson',180)
Output Desired
Person with max sum amount
ted mosby // As ted mosby sum = 450 (100 + 350), which is largest
I tried
Select first_name, last_name from mock_sales group by first_name, last_name where amount in (
select max(amount) from t
(select sum(amount) as amount from mock_sales as t group by first_name, last_name)
or
select t.first_name, t.last_name from mock_sales where max(amount) == t.amount and t.amount in (
Select first-name, last_name, sum(amount) as amount from mock_sales as t group by first_name, last_name)
But they both gave syntax errors. Any help will be appreciated.
Having trouble joining the result of 2 queries.
You can just group records having the same first/last name, order the results and keep the first row only:
select first_name, last_name, sum(amount) total_amount
from mock_sales
group by first_name, last_name
order by total_amount desc
limit 1
If you want to allow ties, then it is a bit different. In Postgres, you can use window functions:
select *
from (
select first_name, last_name, sum(amount) total_amount,
rank() over(order by sum(amount) desc) rn
from mock_sales
group by first_name, last_name
) t
where rn = 1
Since you want the sum instead of max value so, try this instead:
SELECT first_name,last_name, SUM(amount) AS amount FROM mock_sales
GROUP BY first_name,last_name ORDER BY amount DESC LIMIT 1;

SQL oracle: Need to display a query.

so i have 3 tables linked together named office, employee, and dependent.
office: Oid (PK), officeName
employee: EID(PK), Fname, Lname, JobTitle, Salary, DOH, Gender, DOB, OID(FK1), Supervisor(FK2)
Dependent: DID(PK), Fname, Lname, Gender, EID(FK1)
Here is the link to the picture of the tables:
http://classweb2.mccombs.utexas.edu/mis325/class/hw/hw12a.jpg
I need to display concatenated name and EID of 5 employees with the largest number of dependents, if there is a tie for the five largest, then I need to display all of the tying employees.
I am confused on how to begin. please help :)
thank you in advance
Just break down the problem:
How many dependents an EID has:
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
Add a rank
SELECT EID, C, RANK() OVER (ORDER BY C DESC)
FROM (
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
) S
We want the first 5
SELECT EID
FROM (
SELECT EID, C, RANK() OVER (ORDER BY C DESC) AS R
FROM (
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
) S
) S2
WHERE R <= 5
Now ask for what you want:
SELECT * -- or whatever
FROM Employee
WHERE EID IN (
SELECT EID
FROM (
SELECT EID, C, RANK() OVER (ORDER BY C DESC) AS R
FROM (
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
) S
) S2
WHERE R <=5
) S3
I suggest you run each step and make sure it gives you the expected results.
Ummm I would try something like this:
Select TOP 5
a.FNAME,
a.LNAME,
a.EID,
Count(b.EID) as Dependents
FROM employee a
LEFT JOIN dependent b on a.EID = b.EID
group by 1,2,3 order by Dependents desc

how to find people with the same first and last name

so i had a table with 3 columns:
id \ first_name \ last_name
and i need to find how many of people share the same full name.
i had something like this:
SELECT COUNT(*)
FROM ACTOR
WHERE FIRST_NAME IN (SELECT FIRST_NAME,LAST_NAME
FROM ACTOR
HAVING COUNT(FIRST_NAME,LAST_NAME) >1);
Use GROUP BY
SELECT FIRST_NAME, LAST_NAME, Count(*) AS CNT
FROM ACTOR
GROUP BY FIRST_NAME, LAST_NAME
HAVING COUNT(*) > 1
This returns the first- and lastname and how often they appear for all which have duplicates. If you only want to know how many that are you can use:
In SQL-Server:
SELECT TOP 1 COUNT(*) OVER () AS RecordCount -- TOP 1 because the total-count is repeated for every row
FROM ACTOR
GROUP BY FIRST_NAME, LAST_NAME
HAVING COUNT(*) > 1
all others:
Select COUNT(*) AS RecordCount
From
(
SELECT FIRST_NAME, LAST_NAME
FROM ACTOR
GROUP BY FIRST_NAME, LAST_NAME
HAVING COUNT(*) > 1
) As X
Use concatenate and group by
select id,FIRST_NAME,LAST_NAME,count(*)
from
(
select id,FIRST_NAME,LAST_NAME,FIRST_NAME||LAST_NAME as full_name
from
actor)x
group by id,FIRST_NAME,LAST_NAME
having count(*) > 1;
Try this:
SELECT COUNT(*) as Totals, NAME
FROM
(SELECT FIRST_NAME+LAST_NAME AS NAME
FROM ACTOR)A
GROUP BY NAME
There are several possibilities for fixing your approach. I think the best to learn is EXISTS:
SELECT COUNT(*)
FROM ACTOR a
WHERE EXISTS (SELECT 1
FROM ACTOR a2
WHERE a2.FIRST_NAME = a.FIRST_NAME AND a2.LAST_NAME = a.LAST_NAME AND
a2.id <> a.id
);

Running Order by on column alias

I am trying to run following SQL query on northwind database :
SELECT * FROM (
SELECT DISTINCT ROW_NUMBER() OVER (ORDER BY Joinning DESC) rownum,
LastName, Country, HireDate AS Joinning
FROM Employees
WHERE Region IS NOT NULL
) r
It's giving me the error :
Invalid column name 'Joinning'.
The 'rownumber' is required for pagination.
Can anybody please suggest how I can sort on the Joining alias with the rownumber generated ?
--A possible work around
Just figured out a work around; please suggest if anything is wrong or need changes :
SELECT ROW_NUMBER() OVER (ORDER BY Joinning DESC) rownum,* FROM (
SELECT
LastName, Country, HireDate AS Joinning
FROM Employees
WHERE Region IS NOT NULL
) r
--To put further where clause on row number(what I wanted to do for pagination):
With myres as(
SELECT ROW_NUMBER() OVER (ORDER BY Joinning DESC) rownum,* FROM (
SELECT
LastName, Country, HireDate AS Joinning
FROM Employees
WHERE Region IS NOT NULL
) a
) Select * from myres where myres.rownum > 0 and myres.rownum < = 0+20
Try
SELECT * FROM (
SELECT DISTINCT ROW_NUMBER() OVER (ORDER BY HireDate DESC) rownum,
LastName, Country, HireDate AS Joinning
FROM Employees
WHERE Region IS NOT NULL
) r
Hope you ahve joinning in your table.
The order by clause is usually given at the last of the query like this :
SELECT * FROM (
SELECT DISTINCT ROW_NUMBER() rownum,
LastName, Country, HireDate AS Joinning)
FROM Employees
WHERE Region IS NOT NULL ORDER BY Joinning DESC)
Hope this helps you!
Use Original Name of the field, That will work just fine HireDate
SELECT * FROM (
SELECT DISTINCT ROW_NUMBER() OVER (ORDER BY HireDate DESC) rownum,
LastName, Country, HireDate AS Joinning
FROM Employees
WHERE Region IS NOT NULL
) r