Select * from a table using data from specific entry in table - sql

I have an author table
| au_id | au_fname | au_lname | city | state |
what i am trying to do is get a query of first and last names based on who lives in the same state as Sarah
Heres what I have so far:
SELECT AU_FNAME, AU_LNAME FROM authors WHERE "STATE" like 'CA'
I don't want to use a static state in my code, I want it to be based on the selected person - Sarah in this case.
Thanks

Use a Sub-Query to find the state of Sarah and filter that state
Try this
SELECT AU_FNAME, AU_LNAME
FROM authors
WHERE STATE in (select state from authors where au_fname = 'Sarah')

SELECT AU_FNAME, AU_LNAME FROM authors WHERE STATE in (select state from authors where au_fname = 'sarah')
or
select a1.AU_FNAME, a1.AU_LNAME FROM authors a1
inner join authors a2 on a1.state = a2.state
where a2.au_fname = 'sarah'

If there is only one "Sarah", then it is best to use = rather than in:
select a.AU_FNAME, a.AU_LNAME
from authors a
where a.state = (select a2.state from authors a2 where a2.au_fname = 'Sarah');
Of course, if there could be more than one Sarah, then in is needed. But = often has better performance, because the database engine knows to search for a single value.

The question is defined a bit vaguely, so based on a qualified guess, it seems asking for the solution to retrieve data rows (containing either ALL data fields, i.e. SELECT * as per the title, or just first/last names as per description, i.e. SELECT AU_FNAME, AU_LNAME) for the states related to some au_fname (e.g. Sarah) passed as a parameter to a SQL query. In the most general case, there can be multiple different authors with the same first name related to multiple different states. Based on this assumption, the query/sub-query may look like
SELECT * FROM authors
WHERE STATE IN (SELECT [state] from authors WHERE au_fname = #afname)
The exact syntax may depend on the specifics of the Database used in the solution.

An inner join would be my first choice over a subquery... some db engines have poor performance with subqueries (older MySQL versions come to mind), but just about any engine ought to be optimized for an inner join:
SELECT a1.AU_FNAME, a1.AU_LNAME
FROM Authors AS a1
INNER JOIN Authors AS a2 ON a1.state = a2.state
WHERE a2.au_fname = 'sarah'
GROUP BY a1.AU_FNAME, a1.AU_LNAME;

Related

Find potential duplicate names in database

I have two tables in a SQL Server Database:
Table: People
Columns: ID, FirstName, LastName
Table: StandardNames
Columns: Nickname, StandardName
Sample Nicknames would be Rick, Rich, Richie when StandardName is Richard.
I would like to find duplicate contacts in my People table but replace any of the nicknames with the standard name. IE: sometimes I have Rich Smith other times it is Richard Smith in the People table. Is this possible? I realize it might be multiple joins to the same table but can't figure out how to start.
Firstly, you need to determine how many duplicates you have in your People table...
SELECT p.FirstName, COUNT(*)
FROM People AS p
INNER JOIN StandardNames AS sn
ON CHARINDEX(sn.Nickname, p.FirstName) > 0 OR
CHARINDEX(sn.Nickname, p.LastName) > 0
GROUP BY p.FirstName
HAVING COUNT(*) > 1
That's just to get an idea of what data you're trying to find in relation to the Nicknames that may possibly exist inside (as a wildcard word search) the Firstname and Lastname columns.
If you are happy with the items found then expand on the query to update the values.
Let's say you wanted to change the Firstname to be the Standardname...
UPDATE p2
SET p2.FirstName = p2.Standardname
FROM
(SELECT p.ID, sn.StandardName
FROM People AS p
INNER JOIN StandardNames AS sn
ON CHARINDEX(sn.Nickname, p.FirstName) > 0 OR
CHARINDEX(sn.Nickname, p.LastName) > 0) AS a
INNER JOIN People AS p2 ON p2.ID = a.ID
So this will obviously find all the People IDs that have a match based on the query above, and it will update the People table by replacing the FirstName with the StandardName.
However, there are issues with this due to the limitation of your question.
the StandardNames table should have its own ID field. All tables should have an ID column as its primary table. That's just my view.
this is only going to work for data it matches using the CHARINDEX() function. What you really need is something to find based on a "sound" or similarity to the nicknames. Check out the SOUNDEX() function and apply your logic from there.
And this is assuming your IDs above are unique!
Good luck
You could standardize the names by joining, and count the number of occurrences. Extracting the ID is a bit fiddly, but also quite possible. I'd suggest the following - use a case expression to find the contact with the standard name, and if you don't have one, just take the id of the first duplicate:
SELECT COALESCE(MIN(CASE FirstName WHEN StandardName THEN id END), MIN(id)),
StandardName,
LastName,
COUNT(*)
FROM People p
LEFT JOIN StandardNames s ON FirstName = Nickname AND
GROUP BY StandardName, LastName

SQL - Nested Sub-Queries

Using postgresql, I have to create a view called 'no_cat_customers' that returns the first name, last name of any customer who has not been shipped any edition of the book named 'The Cat in the Hat'. This should be done using universal quantification. The error I'm getting is - "ERROR: EXCEPT types integer and text cannot be matched" in reference to line 7 (EXCEPT (SELECT shipments.isbn).
CREATE VIEW no_cat_customers(customer_first_name, customer_last_name)
AS SELECT first_name, last_name
FROM customers
WHERE EXISTS (SELECT c_id
FROM shipments
WHERE customers.c_id = shipments.c_id
EXCEPT (SELECT shipments.isbn
FROM books, editions, shipments
WHERE books.book_id = editions.book_id AND
editions.isbn = shipments.isbn AND
title LIKE '%The Cat in the Hat%'));
I understand that this is hard to ask considering you don't have the database I'm using, but any help with this would be very much appreciated!
EDIT: I should add that there is two editions of 'The Cat in the Hat' in the database, both with different isbn's. So that has to be taken into account.
Use explicit JOIN syntax instead of mixing it with real conditions in where clause. I believe that this should work:
CREATE VIEW no_cat_customers(customer_first_name, customer_last_name) AS
SELECT first_name, last_name
FROM customers c
WHERE NOT EXISTS (
SELECT 1
FROM shipments s
JOIN editions e ON s.isbn = e.isbn
JOIN books b ON b.book_id = e.book_id
WHERE b.title ILIKE '%The Cat in the Hat%'
AND c.c_id = s.c_id
)
If you have datatype errors, cast your columns to appropriate types before comparing them.

SQL Slightly complicated query

Question: Write a query to find academics that are authors and that have only ever coauthored papers with authors from institutes in the same state as their own. List their academic number, title and last name.
I've been working on this question for some time and I haven't been able to think of a proper query.
My schema for the database (tables) I need to use:
ACADEMIC(ACNUM, DEPTNUM, FAMNAME, TITLE)
DEPARTMENT(DEPTNUM, STATE)
AUTHOR(PANUM, ACNUM)
There are multiple ACNUM's (Account number) for 1 PANUM (Page number) inside the Author table.
I tried planning it and all I could think of was something along the lines of this:
Need to loop through Author table,
SELECT PANUM
FROM AUTHOR A
Then need to find all authors of that paper:
SELECT ACNUM
FROM AUTHOR B
WHERE PANUM = A.PANUM;
Then need to intersect all states:
SELECT DEPTNUM, TITLE, FAMNAME, UPPER(STATE)
FROM ACADEMIC C, DEPARTMENT D
WHERE C.ACNUM = B.ACNUM AND D.DEPTNUM = C.DEPTNUM;
Could you guys give me some assistance on how I could do something like this? I appreciate any help.
EDIT: Some more information
I haven't actually figured out a desired result as theres hundreds of rows of data. Essentially, I have to query the database by: Selecting page number from Author table, then finding all Account Number's that the Author table has for that page number, then using all these account numbers I need to make sure they are all in the same state. E.g. Account 100 and 101 worked on page number 300 together and both are in state VIC, thus I would list the academics information (famname, title and acnum)
You need to query out a table joining the ACADEMIC, DEPARTMENT, and AUTHOR tables, and then self-join that table by paper, restricting on state, to obtain the result you want:
SELECT DISTINCT t1.FAMNAME, DISTINCT t1.TITLE FROM
(ACADEMIC a1 INNER JOIN DEPARTMENT d1 ON a1.DEPTNUM = d1.DEPTNUM
INNER JOIN AUTHOR auth1 ON a1.ACNUM = auth1.ACNUM) t1
INNER JOIN
(ACADEMIC a2 INNER JOIN DEPARTMENT d2 ON a2.DEPTNUM = d2.DEPTNUM
INNER JOIN AUTHOR auth2 ON a2.ACNUM = auth2.ACNUM) t2
GROUP BY t1.PANUM
HAVING COUNT(DISTINCT t2.STATE) = 1;

Query to output unmatched column names

I have a table with two of the columns lets say Country, Country Code. The table can have multiple rows with same country and code. But country and code always have to match. How can I write a query that will find me a list of all rows where country and country code do not match.
If this is the table, I want the query to return row#4.. where Canada does not match with XYZ (it should have been CN).. There is a master list of country and codes in a different table lets say.. tblCountries.
You can either use the select statement with the NOT EXISTS operator as suggested by Aaron Bertrand in the comments, or you can use a left join:
SELECT T.*
FROM MyTable T
LEFT JOIN TblCountries C ON(T.Country = C.Country AND T.CountryCode = C.CountryCode)
WHERE C.CountryId IS NULL -- Assuming you have a column by that name that's not nullable.
Giorgi Nakeuri's answer will also get you the result you are looking for, however, if there is a record in your table that have a country and a code that doesn't even exist in tblCountry then Aaron's answer or mine will return it, but Giorgi's will not.
First of all if there is another table with contry and code then you are breaking normalization principles having same columns in another table.
You can do it like:
select * from testTable tt
join Countries c on ((c.Country = tt.Country and c.Code <> tt.Code)
or (c.Code = tt.Code and c.Country <> tt.Country))

SQL Query multiple tables same values

I'm having an issue creating a query. Here are the specifics.
There are 2 tables company_career and company_people.
People contains person information (Name, Address, etc) and Career contains historical career information (job_title, department, etc.)
People is linked to Career by job_ref_id.
Direct_Report_id lies in the career table and contains a unique id that correlates to job_ref_id.
Example: job_ref_id = '1' results in direct_report_id ='A'. I then use the value produced from direct-report_id (i.e., 'A') and query the job_ref_id = 'A' and this produces the employee name. Since it produces the employee name (which is actually the manager) I need to know how I would query this to present this as the manager name.
I think I know what you are looking for, you just need to use joins and aliases. For example:
SELECT
cp.name AS [EmployeeName],
cp.address AS [EmployeeAddress],
cc.job_title AS [EmployeeTitle],
cc.department AS [EmployeeDept],
m.name AS [ManagerName]
FROM company_people cp
LEFT JOIN company_career cc ON cc.job_ref_id = cp.job_ref_id
LEFT JOIN company_people m ON m.job_ref_id = cc.direct_report_id