SQL Comparing Information in Tables - sql

I want to know how I would compare two pieces of information such as say I have two columns in my query: surname and forename. How could I check to see whether the forename exists in the surname column and visa versa?
So far I've created two temporary tables, one which selects just the surname, and one which selects all the other information. I was going to compare them by doing a join but im having no luck.

Something like:
Select u1.Surname, u1.Forename,
(select count(0) from users u2 where u1.surname = u2.forename) as CountWhereForenameEqualsMySurname,
(select count(0) from users u2 where u1.forename = u2.surname ) as CountWhereSurnameEqualsMyForename
From users u1

Without knowing the structure of your tables it is a little difficult to write a query. But I would do something like this; join the table to itself based on the surname being equal to the forename.
SELECT
t1.forename as foreName1,
t1.surname as surName1,
t2.forename as foreName2,
t2.surname as surName2
FROM
tableName as t1 INNER JOIN tablename as t2
ON
t1.surname = t2.forename

Related

Remove duplicates from result in sql

i have following sql in java project:
select distinct * from drivers inner join licenses on drivers.user_id=licenses.issuer_id
inner join users on drivers.user_id=users.id
where (licenses.state='ISSUED' or drivers.status='WAITING')
and users.is_deleted=false
And result i database looks like this:
And i would like to get only one result instead of two duplicated results.
How can i do that?
Solution 1 - That's Because one of data has duplicate value write distinct keyword with only column you want like this
Select distinct id, distinct creation_date, distinct modification_date from
YourTable
Solution 2 - apply distinct only on ID and once you get id you can get all data using in query
select * from yourtable where id in (select distinct id from drivers inner join
licenses
on drivers.user_id=licenses.issuer_id
inner join users on drivers.user_id=users.id
where (licenses.state='ISSUED' or drivers.status='WAITING')
and users.is_deleted=false )
Enum fields name on select, using COALESCE for fields which value is null.
usually you dont query distinct with * (all columns), because it means if one column has the same value but the rest isn't, it will be treated as a different rows. so you have to distinct only the column you want to, then get the data
I suspect that you want left joins like this:
select *
from users u left join
drivers d
on d.user_id = u.id and d.status = 'WAITING' left join
licenses l
on d.user_id = l.issuer_id and l.state = 'ISSUED'
where u.is_deleted = false and
(d.user_id is not null or l.issuer_id is not null);

How do I check for occurrence in two tables simultaneously

I have a SQL query (oracle) that checks for both persons and firms, the problem is that you won't find a company in the user table and the other way around.
As of now I write this in two queries, but I would like to make this into one query (for example if I can get some help creating a temporay table)
I have a info table that tells me if this is a user, a company or both
The sql looks a bit like this:
Table1:
fk_id,
info1,
info2,
info3
Info_table:
fk_id,
<info if user, company or both>
User_table:
firstname,
lastname,
adress,
fk_id
Company_table:
Companyname,
adress,
fk_id
I would like to eighter 1:
Make a temporary table that looks like this:
Temptable:
fk_id,
firstname(if user or both, else empty),
lastname(if user, else companyname),
adress
or make a query like this:
select table1.info1, table1.info2, firstname, lastname, adress
from table1,
user_table,
company_table,
info_table
where table1.fk_id = user_table.fk_id (if user or both)
or table1.fk_id = company_table.fk_id (if company)
Any tips on how to solve this would be great. What is the best solution (making a temp table or to add this into the initial query)?
Use left outer join (in this response i'll use the + operator for convenience)
select table1.info1, table1.info2,
firstname,
nvl(lastname,company_name) lastname,
nvl(user_table.adress,company_table.adress) adress
from table1,
user_table,
company_table,
info_table
where
table1.fk_id=info_table.fk_id(+)
and table1.fk_id = user_table.fk_id(+) --(if user or both)
and table1.fk_id = company_table.fk_id(+) --(if company)
You can use a union:
quick example:
select firstname
,lastname as name
,'person_table' as source_table
from person_table
union
select null
,company_name
,'company_table'
from company_table;
The result will be a list of both persons and companies.
The correct way to write this query:
select t1.info1, t1.info2, ut.firstname,
coalesce(ut.lastname, ct.company_name) as lastname,
coalesce(ut.adress, ct.adress) as address
from table1 t1 left join
info_table it
on t1.fk_id = it.fk_id left join
user_table ut
on t1.fk_id = ut.fk_id and
it.info in ('both', 'user') left join
company_table ct
on t1.fk_id = ct.fk_id and
ct.info in ('both', 'company') ;
Notes:
This uses proper, explicit, standard JOIN syntax, as recommended by Oracle itself.
This only does the joins when the type specifies that the join is appropriate.
This uses COALESCE(), a standard function, rather than the bespoke NVL().
All column names are qualified.
This uses table aliases, so the query is easier to write and to read.

Is it true that JOINS can be used everywhere to replace Subqueries in SQL

I heard people saying that table joins can be used everywhere to replace sub-queries. I tested it in my query, but found that appropriate data set was only retrieved when I used sub-queries. I was not able to get same data set using joins. I am not sure if what I found is right because I am a newcomer in RDBMS, thus not so much experienced. I will try to draw the schema (in words) of the database in which I was experimenting:
The database has two tables:
Users (ID, Name, City) and Friendship (ID, Friend_ID)
Goal: Users table is designed to store simple user data and Friendship table represents Friendship between users. Friendship table has both the columns as foreign keys, referencing to Users.ID. Tables have many-to-many relationship between them.
Question: I have to retrieve Users.ID and Users.Name of all the Users, which are not friends with a particular user x, but are from same city (much like fb's friend suggestion system).
By using subquery, I am able to achieve this. Query looks like:
SELECT ID, NAME
FROM USERS AS U
WHERE U.ID NOT IN (SELECT FRIENDS_ID
FROM FRIENDSHIP,
USERS
WHERE USERS.ID = FRIENDSHIP.ID AND USERS.ID = x)
AND U.ID != x AND CITY LIKE '% A_CITY%';
Example entries:
Users
Id = 1 Name = Jon City = Mumbai
Id=2 Name=Doe City=Mumbai
Id=3 Name=Arun City=Mumbai
Id=4 Name=Prakash City=Delhi
Friendship
Id= 1 Friends_Id = 2
Id = 2 Friends_Id=1
Id = 2 Friends_Id = 3
Id = 3 Friends_Id = 2
Can I get the same data set in a single query by performing joins. How? Please let me know if my question is not clear. Thanks.
Note: I used inner join in the sub-query by specifying both tables: Friendship, Users. Omitting the Users table and using the U from outside, gives an error (But if not using alias for the table Users, query becomes syntactically okay but result from this query includes ID's and names of users, who have more than one friends, including the user having ID x. Interesting, but is not the topic of the question).
For not in you can use left join and check for is null:
select u.id, u.name
from Users u
left join Friends f on u.id = f.id and f.friend_id = #person
where u.city like '%city%' and f.friend_id is null and u.id <> #person;
There are some cases where you can't work out your way with just inner/left/right joins, but your case is not one of them.
Please check sql fiddle: http://sqlfiddle.com/#!9/1c5b1/14
Also about your note: What you tried to do can be achieved with lateral join or cross apply depending on the engine you are using.
You can rewrite your query using only joins. The trick is to join to the User tables once with an inner join to identify users within the same city and reference the Friendship table with a left join and a null check to identify non-friends.
SELECT
U1.ID,
U1.Name
FROM
USERS U1
INNER JOIN
USERS U2
ON
U1.CITY = U2.CITY
LEFT JOIN
FRIENDSHIP F
ON
U2.ID = F.ID AND
U1.ID = F.FRIEND_ID
WHERE
U2.id = X AND
U1.ID <> U2.id AND
F.id IS NULL
The above query doesn't handle the situation where USER x's primary key is in the FRIEND_ID column of the FRIENDSHIP table. I assume because your subquery version doesn't handle that situation, perhaps you create 2 rows for each friendship, or friendships are not bi-directional.
Joins and subqueries can be used to achieve similar results in some cases, but certainly not all. As an example, this query with a subquery could not be achieve vis-a-vis a join:
SELECT ID, COLUMN1, COUNT(*) FROM MYTABLE
WHERE ID IN (
SELECT DISTINCT ID FROM MYTABLE
WHERE COLUMN2 NOT IN (VALUES1, VALUES2)
)
GROUP BY ID;
This is only one example, but there are many.
Conversely, you cannot get information from another table by using a subquery without joining it.
As to your example
SELECT ID, NAME FROM USERS AS U
WHERE U.ID NOT IN (
SELECT FRIENDS_ID FROM FRIENDSHIP, USERS
WHERE USERS.ID = FRIENDSHIP.ID AND USERS.ID = x)
AND U.ID != x AND CITY LIKE '% A_CITY%';
This could be constructed as:
select ID, NAME from users u
join FRIENDSHIP f on f.ID = u.ID
where u.ID = x
and u.ID != y
and CITY like '%A_CITY';
I changed your second x to a y assumptively, so it wouldn't cause confusion.
Of course, you may also want to LEFT JOIN aka LEFT OUTER JOIN if there is a chance that there may be multiple results in the FRIENDSHIP table.

Combine 2 SQL SELECT statements

** Evidently some people think my question is not worthy of their time. I whole heartedly appologise for this. However, rather than down voting why not use that time to do something positive and at least tell me what info you would require to make this not be a cr#p question in your eyes. **
I have a list of staff in table tblMembers and a list of clients in table tblClients.
One person may have several client.
The staff member associated with a client is identified by staffId against the client record.
Each staff member has a category Id for the type of clients they have catId.
I need to find all of the staff for a given client type and then sort them by the number of clients they have. Staff members without any clients should show a result of 0 rather than not showing.
A simplified table structure would be:
tblMembers:
Id | catId
tblClients:
Id | staffId
Any help would be greatly appreciated.
Thanks!
Try this:
SELECT m.Id 'Member Id', ISNULL(c.StaffCount, 0) 'StuffCount'
FROM tblMembers m
LEFT JOIN
(
SELECT staffId, COUNT(staffId) 'StaffCount'
FROM tblClients
GROUP BY staffId
) c ON m.Id = c.staffId
WHERE m.Cat = 'Some Id'
ORDER BY StuffCount
Its fairly simple to do a join/group and count
SELECT
s.id,
s.catid,
COUNT(c.id)
FROM
tblMembers s
LEFT JOIN tblClients c
ON s.id = c.staffid
WHERE
s.catid = #catID
GROUP BY
s.id,
s.catid
ORDER BY
COUNT(c.id) desc
However the one tricky bit is
show a result of 0 rather than not showing.
To do this you need to do a left join to make sure they show even if there are no matching records and you need to make sure to count a field on the table on the Right side of the join. Otherwise you'd get a count of 1
DEMO
Hope I correctly understood your case.
Try something like this:
SELECT T1.ID,
Count(*)
FROM MEMBERS T1
INNER JOIN CLIENTS T2
ON T1.ID = T2.STAFFID
WHERE T1.CATID = 2
GROUP BY T1.ID
UNION
SELECT DISTINCT ID,
0
FROM MEMBERS
WHERE CATID != 2
A working sample is available here.
try:
select tblMembers.id, count(tblClient.id)
from tblMembers left join tblCLient on staffId = tblMembers.id
where tblMembers.catId = ??
group by tblMembers.id
order by 2 desc

Simple SQL Problem

I have a SQL query that I cant wrap my mind around. I do not have a large amount of sql experience. So I need some help
I have a table XXX:
Social Security No (SSN).
Name.
organisation. (Finance/IT)
In english what I want is:
To select all SSNs and Names in "Finance" where there is a different name for that SSN in "IT".
My not working attempt:
select ssn , name from XXX where org = "Finance" and name not in (select name from XXX where org="IT" and ssn=the_first_ssn)
Please help.
I have decided to make it a bit more difficult.
SSN can ocur multiple times in "IT":
So I want to select all SSNs and Names in Finance where the SSN does not exist with the same Name in "IT"
You could use a subquery in an exists clause:
select ssn, name
from YourTable a
where organisation = 'Finance'
and exists
(
select *
from YourTable b
where organisation = 'IT'
and a.ssn = b.ssn
and a.name <> b.name
)
The subquery says there must be a row in IT with the same SSN but a different name.
Assuming ssn is a unique key...
select ssn, name
from XXX XXX1
where org = "Finance"
and ssn in
(
select ssn
from XXX XXX2
where org="IT"
and XXX1.name<>XXX2.name
)
SELECT distinct
t1.ssn,
t1.name
from
xxx t1
inner join xxx t2 on t1.ssn=t2.ssn and t1.name<>t2.name
where t1.org='Finance' and t2.org='IT'
I know I'm late to the party, but I'm working on learning SQL and I wanted to try my hand at a solution and compare against the existing answers. I created a table Personnel with some testing data.
My SQL Server only query uses CTEs and an INNER JOIN:
WITH
Finance AS (SELECT SSN, Name FROM Personnel WHERE Org = 'Finance'),
IT AS (SELECT SSN, Name FROM Personnel WHERE Org = 'IT')
SELECT Finance.SSN, Finance.Name
FROM Finance
INNER JOIN IT ON IT.SSN = Finance.SSN
WHERE IT.Name != Finance.Name
Alexander's solution uses a straight INNER JOIN. I rewrote it a little bit, putting the name comparison in the WHERE clause, and dropping DISTINCT because it's not required:
SELECT Finance.SSN, Finance.Name
FROM Personnel Finance
INNER JOIN Personnel IT ON Finance.SSN = IT.SSN
WHERE
(Finance.Org = 'Finance' AND IT.Org = 'IT') AND
(Finance.Name != IT.Name)
Andomar's solution using a correlated subquery inside an EXISTS clause:
SELECT SSN, Name
FROM Personnel a
WHERE
(Org = 'Finance') AND
EXISTS
(
SELECT *
FROM Personnel b
WHERE (Org = 'IT') AND (a.SSN = b.SSN) AND (a.Name != b.Name)
)
barrylloyd's solution using a correlated subquery inside an IN clause:
SELECT SSN, Name
FROM Personnel p1
WHERE
(Org = 'Finance') AND
SSN IN
(
SELECT SSN FROM Personnel p2
WHERE (Org = 'IT') AND (p1.Name != p2.Name)
)
I plugged all of these into SQL Server, and it turns out that queries 1 and 2 both generate the same query plan, and queries 3 and 4 generate the same query plan. The difference between the two groups is the former group actually does an INNER JOIN internally, while the latter group does a left semi-join instead. (See here for an explanation of the different types of joins.)
I'm assuming there is a slight performance advantage favouring the left semi-join; however, for the business case, if you want to see any data columns from the right table (for example, if you want to display both names to compare them), you would have to completely rewrite those queries to use an INNER JOIN-based solution.
So given all that, I would favour solution 2, because the performance is so similar to 3 and 4, and it's far more flexible than those as well. My solution makes the SELECT statement very easy to read, but it's more verbose than 2 and not as portable. I suppose that mine might be better for readability if you have to do additional filtering on each of the two "sub-tables," or if the results of this query are going to be used as an intermediate step to a further goal.