How to return a count of duplicates and unique values into a column in Access - sql

I currently have this table:
First_Name
Last_Name
Jane
Doe
John
Smith
Bob
Smith
Alice
Smith
And I'm looking to get the table to look for duplicates in the last name and return a value into a new column and exclude any null/unique values like the table below, or return a Yes/No into the third column.
First_Name
Last_Name
Duplicates
Jane
Doe
0
John
Smith
3
Bob
Smith
3
Alice
Smith
3
OR
First_Name
Last_Name
Duplicates
Jane
Doe
No
John
Smith
Yes
Bob
Smith
Yes
Alice
Smith
Yes
When I'm trying to enter the query into the Access Database, I keep getting the run-time 3141 error.
The code that I tried in order to get the first option is:
SELECT first_name, last_name, COUNT (last_name) AS Duplicates
FROM table
GROUP BY last_name, first_name
HAVING COUNT(last_name)=>0

You can use a subquery. But I would recommend 1 instead of 0:
select t.*,
(select count(*)
from t as t2
where t2.last_name = t.last_name
)
from t;
If you really want zero instead of 1, then one method is:
select t.*,
(select iif(count(*) = 1, 0, count(*))
from t as t2
where t2.last_name = t.last_name
)
from t;

Related

Filtering SQL rows based on values from other rows

Using a SQL Server 2016 SP1 database I have this data in table name AgentsTable:
SELECT * FROM AgentsTable;
user_id first_name last_name agent_id agent_status agent_code
2003015038088 John Brown 22307 Retired 12345
2003015038088 John Brown 22307 Death 12399
4432442556456 Mary Jane 24667 Active 32133
7746234737464 Harry Smith 29981 Retired 42354
3455555657677 Mark Aguy 29654 Active 34655
5436546674465 Sally Sam 22584 Retired 45464
The second row shows that 'John Brown' is dead (agent_status = 'Death'), so I would like to exclude all rows for that agent_id who is dead. (Note that John Brown has two different agent_codes, so there's one row for each agent_code. That's how the source data is...)
This query:
SELECT * FROM AgentsTable WHERE agent_status = 'Retired';
Will return this:
user_id first_name last_name agent_id agent_status agent_code
2003015038088 John Brown 22307 Retired 12345
7746234737464 Harry Smith 29981 Retired 42354
5436546674465 Sally Sam 22584 Retired 45464
The result I want, where John Brown (22307) is excluded, is:
user_id first_name last_name agent_id agent_status agent_code
7746234737464 Harry Smith 29981 Retired 42354
5436546674465 Sally Sam 22584 Retired 45464
How can I achieve that? In other words, how can I exclude one row based on a value in another related row?
You can use CTE and get agents who are not deceased as given below:
;WITH CTE_deceasedagents AS
(
SELECT agent_id
FROM AgentsTable
WHERE agent_status = 'Death'
)
SELECT *
FROM AgentsTable as a
WHERE NOT EXISTS
(
SELECT agent_id
FROM CTE_deceasedagents as c
WHERE c.agent_id = a.agent_id
);
GO
SELECT * FROM AgentsTable t1 WHERE agent_status = 'Retired' where NOT EXISTS (SELECT 1 FROM AgentsTable t2 WHERE t2.agent_status = 'Death' and t2.agent_code = t1. agent_code );
I would just use not exists with a correlated subquery to ensure that no other record exists with the same user_id and a 'Death' status:
select a.*
from agentsTable a
where not exists (
select 1
from agentsTable a1
where a1.user_id = a.user_id and a1.agent_status = 'Death'
)

Oracle Statement to Return Result Depending on Max Value of a Record

I've been stuck here for the whole day.
I have 2 tables:
TABLE 1: LOGS
FIRST_NAME LAST_LOG_IN
------------------------------
John 15-NOV-17
Jane 13-NOV-17
John 12-NOV-17
John 11-NOV-17
John 10-NOV-17
Jane 12-NOV-17
TABLE 2: USER
FIRST_NAME LAST_NAME
------------------------------
Jane Doe
John Smith
The Requirements are:
If today is 22-NOV-17, I need to get the FIRST_NAME, LAST_NAME
and LAST_LOG_IN(in 'YYYY-MM-DD HH24:MI:SS' format) of the user
only if his/her LAST_LOG_IN is earlier than the last 7 days
Put only in one statement to execute in SQL Developer (not using PL/SQL)
so the Expected Output should be:
FIRST_NAME LAST_NAME LAST_LOG_IN
---------------------------------------------------
Jane Doe 2017-11-13 17:49:57
Something like:
select u.first_name, u.last_name, to_char(a.log_date,'YYYY-MM-DD HH24:MI:SS') from (
select first_name, max(last_log_in) log_date from logs group by first_name) a
inner join
user u on (a.first_name = u.first_name)
where a.log_date > sysdate - 7;

pl/sql query to remove duplicates and replace the data

I have the following table:
data_id new_data_id first_name last_name
1 john smith
2 john smith
3 john smith
4 jeff louis
5 jeff louis
6 jeff louis
The above table has duplicate first and last names, and the data_id is different for all of them. In order to remove these duplicates, I would need to write a SQL query to replace the highest data_id in new_data_id column. My output would look something like this:
data_id new_data_id first_name last_name
1 3 john smith
2 3 john smith
3 3 john smith
4 6 jeff louis
5 6 jeff louis
6 6 jeff louis
How would I do this?
What you're looking for is an Oracle analytic function.
The aggregate function MAX can be used to select the highest data_id from your entire resultset, but that's not exactly what you need. Instead, use its alter ego, the MAX analytic function like so:
SELECT
data_id,
MAX(data_id) OVER (PARTITION BY first_name, last_name) AS new_data_id,
first_name,
last_name
FROM employees
ORDER BY data_id
This works by "partitioning" your resultset by first_name and last_name, and then it performs the given function within that subset.
Good luck!
Here's a fiddle: http://sqlfiddle.com/#!4/48b29/4
More info can be found here:
http://docs.oracle.com/cd/E11882_01/server.112/e41084/functions004.htm#SQLRF06174
If you need a change in place, a correlated update is probably the simplest way to write that:
UPDATE T
SET "new_data_id" =
(SELECT MAX("data_id") FROM T T2
WHERE T2."first_name" = T."first_name"
AND T2."last_name" = T."last_name")
See http://sqlfiddle.com/#!4/51a69/1

Select query which returns exect no of rows as compare in values of sub query

I have got a table named student. I have written this query:
select * From student where sname in ('rajesh','rohit','rajesh')
In the above query it's returning me two records; one matching 'rajesh' and another matching: 'rohit'.
But i want there to be 3 records: 2 for 'rajesh' and 1 for 'rohit'.
Please provide me some solution or tell me where i am missing.
NOTE: the count of result of sub query is not fix there can be many words there some distinct and some multiple occurrence .
Thanks
Your requirements are not clear, and I'll try to explain why.
Let's define table students
ID FirstName LastName
1 John Smith
2 Mike Smith
3 Ben Bray
4 John Bray
5 John Smith
6 Bill Lynch
7 Bill Smith
Query with WHERE clause:
FirstName in ('Mike', 'Ben', 'Mike')
will return 2 rows only, because it could be rewritten as:
FirstName='Mike' or FirstName='Ben' or FirstName='Mike'
WHERE is filtering clause that just says if existing row satisfy given conditions or not (for each of rows created by FROM clause.
Let's say we have subquery that returns any number of non distinct FirstNames
In case if SQ contains 'Mike', 'Ben', 'Mike' using inner join you can get those 3 rows without problem
Select ST.* from Students ST
Inner Join (Select name from …. <your subquery>) SQ
On ST.FirstName=SQ.name
Result will be:
ID FirstName LastName
2 Mike Smith
2 Mike Smith
3 Ben Bray
Note data are not ordered by order of names returning by SQ. If you want that, SQ should return some ordering number, eg.:
Ord Name
1. Mike
2. Ben
3. Mike
In that case query should be:
Select ST.* from Students ST
Inner Join (Select ord, name from …. <your subquery>) SQ
On ST.FirstName=SQ.name
Order By SQ.ord
And result:
ID FirstName LastName
2 Mike Smith (1)
3 Ben Bray (2)
2 Mike Smith (3)
Now, let's se what will happen if subquery returns
Ord Name
1. Mike
2. Bill
3. Mike
You will end up with
ID FirstName LastName
2 Mike Smith (1)
6 Bill Lynch (2)
7 Bill Smith (2)
2 Mike Smith (3)
Even worse, if you have something like:
Ord Name
1. John
2. Bill
3. John
Result is:
ID FirstName LastName
1 John Smith (1)
4 John Bray (1)
5 John Smith (1)
6 Bill Lynch (2)
7 Bill Smith (2)
1 John Smith (3)
4 John Bray (3)
5 John Smith (3)
This is an complex situation, and you have to clarify precisely what requirement is.
If you need only one student with the same name, for each of rows in SQ, you can use something like SQL 2005+):
;With st1 as
(
Select Row_Number() over (Partition by SQ.ord Order By ID) as rowNum,
ST.ID,
ST.FirstName,
ST.LastName,
SQ.ord
from Students ST
Inner Join (Select ord, name from …. <your subquery>) SQ
On ST.FirstName=SQ.name
)
Select ID, FirstName, LastName
From st1
Where rowNum=1 -- that was missing row, added later
Order By ord
It will return (for SQ values John, Bill, John)
ID FirstName LastName
1 John Smith (1)
6 Bill Lynch (2)
1 John Smith (3)
Note, numbers (1),(2),(3) are shown to display value of ord although they are not returned by query.
If you can split the where clause in your calling code, you could perform a UNION ALL on each clause.
SELECT * FROM Student WHERE sname = 'rajesh'
UNION ALL SELECT * FROM Student WHERE sname = 'rohit'
UNION ALL SELECT * FROM Student WHERE sname = 'rajesh'
Try using a JOIN:
SELECT ...
FROM Student s
INNER JOIN (
SELECT 'rajesh' AS sname
UNION ALL
SELECT 'rohit'
UNION ALL
SELECT 'rajesh') t ON s.sname = t.sname
just because you've got a criteria in there two times doesn't mean that it will return 1 result per criteria. SQL engines usually just use the unique criteria - thus, from your example, there will be 2 criteria in IN clause: 'rajesh','rohit'
WHY do you need to return 2 results? are there two rajesh in your table? they should BOTH return then. You don't need to ask for rajesh twice for that to happen. What does your data look like? What do you want to see returned?
Hi i am query just as you give above and it give me all data that matches in the condition of in clause. just like your post
select * from person
where personid in (
'Carson','Kim','Carson'
)
order by FirstName
and its give me all records which fulfill this Criteria

TSQL, counting pairs of values in a table

Given a table in the format of
ID Forename Surname
1 John Doe
2 Jane Doe
3 Bob Smith
4 John Doe
How would you go about getting the output
Forename Surname Count
John Doe 2
Jane Doe 1
Bob Smith 1
For a single column I would just use count, but am unsure how to apply that for multiple ones.
SELECT Forename, Surname, COUNT(*) FROM YourTable GROUP BY Forename, Surname
I think this should work:
SELECT Forename, Surname, COUNT(1) AS Num
FROM T
GROUP BY Forename, Surname