SQL - Compare 2 tables then add unique items to 3rd table - sql

Title kind of says it all.
I have 2 tables Both with matching data
Table Name: Customers
_____________________________
ID | CompanyName
--------------
1 | Joes
2 | Kennys
3 | Kellys
4 | Ricks
5 | Johns
Table Name: OldCustomers
_____________________________
ID | CompanyName
--------------
1 | Joes
2 | Kennys
3 | Kellys
4 | Ricks
I want to do a comparison between the two tables. Then take the Row that doesn't exist in Table 2, and add it to a table i've created called "NewCustomers"

You can use the following:
insert into NewCustomers(id, companyname)
select c.id
, c.companyname
from Customers c
left join OldCustomers oc
on c.companyname = oc.companyname
where oc.id is null;
select *
from NewCustomers
See SQL Fiddle with Demo
This query will find all records where the company name is missing from the OldCustomers table. If you want to join on both id and company name you would just add and c.id = oc.id to the left join. It will give you the same results.

Related

In a PostgreSQL query how to filter results from a field in a join

My table structure is as follows:
Restaurants
| id | name |
|----|---------|
| 1 | The Hut |
| 2 | T Burger|
Dishes:
| id | name |
|----|---------|
| 1 | Pizza |
| 2 | Caramel |
Orders:
| id | locatio |
|----|---------|
| 1 | New York|
| 2 | London |
_RestaurantDishes:
In here, B represents restaurants and A represents dishes.
A restaurant can have many dishes. A dish can only have one restaurant.
| id | A | B |
|----|---|---|
| 1 | 1 | 1 |
| 2 | 1 | 2 |
_DishOrders:
In here, B represents orders and A represents dishes.
A dish can have many orders. An order can have many dishes.
| id | A | B |
|----|---|---|
| 1 | 1 | 1 |
| 2 | 1 | 2 |
What I want to do is, get a list of dishes from a selected list of restaurants and sort them according to the orders count. I tried to do it like this:
SELECT count(dishOrder.id) as myCount, dish.id, name
FROM "default$default"."Dish" dish
left join "default$default"."_RestaurantDishes" dishRestaurant on dish.id = dishRestaurant."A"
left join "default$default"."_DishOrders" dishOrder on dish.id = dishorder."A"
where "dishRestaurant"."B" in ("1", "2")
group by dish.id order by mycount desc;
But it gives me the error ERROR: missing FROM-clause entry for table "dishRestaurant". I tried many other approaches but didn't work.
you are getting error ERROR: missing FROM-clause entry for table "dishRestaurant" because
you used double quote in number in ("1", "2") which turned into column name for using double quote. you have to change it like in (1,2)
SELECT count(dishOrder.id) as myCount, dish.id, name
FROM "default$default"."Dish" dish
left join "default$default"."_RestaurantDishes" dishRestaurant on dish.id = dishRestaurant."A"
left join "default$default"."_DishOrders" dishOrder on dish.id = dishorder."A"
where "dishRestaurant"."B" in (1, 2)
group by dish.id ,name
order by myCount desc;
you also used dish.id, name in selection but not used name in group by, so you have to use that in group by
Don't escape identifiers if you can avoid it. The escaping fixes the casing -- and strange things happen.
I suspect that you want:
select count(*) as myCount, d.id, d.name
from "default$default"."Dish" d left join
"default$default"."_RestaurantDishes" dr
on dr."A" = d.id and
dr."B" in (1, 2) left join
"default$default"."_DishOrders" do
on d.id = do."A"
group by d.id, d.name
order by mycount desc;
Notes:
I simplified the table aliases and removed the double quotes from the aliases defined in the query.
You should remove the double quotes from the column names -- if you can.
I added d.name back into the group by. This is not needed if d.id is unique.
I use count(*), so no columns are referenced.
I moved the filtering condition to the on clause. This keeps the left join intact.

Left Joining table with values in lookup table

I have two tables on SQL-Server. One containing clients, and one a client profile lookup table. So a bit like this (note that Fred doesn't have any values in the lookup table):
Table: Clients Table: Profile
ID | Name | Status ClientID | Type | Value
----------------------- -----------------------
1 | John | Current 1 | x | 1
2 | Peter | Past 1 | y | 2
3 | Fred | Current 2 | x | 3
2 | y | 4
I then am trying to create a tmp table that needs to contain all current clients like this:
ID | Name | TypeY
==================
1 | John | 2
3 | Fred |
My knowledge of SQL is limited, but I think I should be able to do this with a Left Join, so I tried this (#tmpClient is already created):
insert into #tmpClient
select a.ID, a.Name, b.Value
from Clients a
left join Profile b
on a.ID = b.ClientID
where a.Status = 'Current' and b.Type = 'y'
However this will always miss Fred out of the temporary table. I am probably doing something very simple wrong, but as I said I am missing the SQL skills to work this one out. Please can someone help me with getting this query right.
You have to move the predicate concerning the second table of the LEFT JOIN operation from WHERE to ON clause:
insert into #tmpClient
select a.ID, a.Name, b.Value
from Clients a
left join Profile b
on a.ID = b.ClientID and b.Type = 'y'
where a.Status = 'Current'

Count how many times a value appears in tables SQL

Here's the situation:
So, in my database, a person is "responsible" for job X and "linked" to job Y. What I want is a query that returns: name of person, his ID and he number of jobs it's linked/responsible. So far I got this:
select id_job, count(id_job) number_jobs
from
(
select responsible.id
from responsible
union all
select linked.id
from linked
GROUP BY id
) id_job
GROUP BY id_job
And it returns a table with id in the first column and number of occurrences in the second. Now, what I can't do is associate the name of person to the table. When i put that in the "select" from beginning it gives me all the possible combinations... How can I solve this? Thanks in advance!
Example data and desirable output:
| Person |
id | name
1 | John
2 | Francis
3 | Chuck
4 | Anthony
| Responsible |
process_no | id
100 | 2
200 | 2
300 | 1
400 | 4
| Linked |
process_no | id
101 | 4
201 | 1
301 | 1
401 | 2
OUTPUT:
| OUTPUT |
id | name | number_jobs
1 | John | 3
2 | Francis | 3
3 | Chuck | 0
4 | Anthony | 2
Try this way
select prs.id, prs.name, count(*) from Person prs
join(select process_no, id
from Responsible res
Union all
select process_no, id
from Linked lin ) a on a.id=prs.id
group by prs.id, prs.name
I would recommend aggregating each of the tables by the person and then joining the results back to the person table:
select p.*, coalesce(r.cnt, 0) + coalesce(l.cnt, 0) as numjobs
from person p left join
(select id, count(*) as cnt
from responsible
group by id
) r
on r.id = p.id left join
(select id, count(*) as cnt
from linked
group by id
) l
on l.id = p.id;
select id, name, count(process_no) FROM (
select pr.id, pr.name, res.process_no from Person pr
LEFT JOIN Responsible res on pr.id = res.id
UNION
select pr.id, pr.name, lin.process_no from Person pr
LEFT JOIN Linked lin on pr.id = lin.id) src
group by id, name
order by id
Query ain't tested, give it a shot, but this is the way you want to go

SQL Server - OR clause in join confusion

I have the table structure like below
Package
PACK_ID | DESCR | BRAND_ID
1 | Shoes | 20
2 | Cloths| NULL
ITEMS
ITEM_ID | PACK_ID | BRAND_ID
100 | 1 | 10
101 | 1 | NULL
102 | 1 | 10
BRANDS
NAME | BRAND_ID
A | 10
B | 20
I want to write a query to list how many items are there in a package grouped by same brand. If the brand is not defined in the item it should get it from package.
Note: Brand_id in both package and items are nullable
My query is this
SELECT count (*) as count,p.descr as descr,b.name FROM [items] item
inner join [package] p on item.pack_id= p.pack_id
inner join [brands] b on b.brand_id = item.brand_id or b.brand_id = p.brand_id
where p.pack_id = 1
group by b.name,p.descr
and my result is
COUNT | descr | NAME
2 | Shoes | a
3 | Shoes | B
whereas i expect the result to be something like this
COUNT | descr | NAME
2 | Shoes | a
1 | Shoes | B
could you please suggest what is wrong with my code? Thanks in advance.
Try using ISNULL on your join condition:
SELECT count (*) as count,p.pack_id as pack_id,b.name FROM [items] item
inner join [package] p on item.pack_id= p.pack_id
inner join [brands] b on b.brand_id = ISNULL(item.brand_id, p.brand_id)
where p.pack_id = 1
group by b.name,p.pack_id
Your OR was causing it to join to multiple rows, this should use the item by default and then fall back to the package.
I would tend to approach this by getting the brand for both the item and the package. Then decide which one to use in the select:
SELECT count(*) as count, p.descr as descr, coalesce(bi.name, bp.name) as name
FROM [items] item inner join
[package] p
on item.pack_id= p.pack_id left join
[brands] bi
on bi.brand_id = item.brand_id left join
brands bp
on b.brand_id = p.brand_id
where p.pack_id = 1
group by coalesce(bi.name, bp.name), p.descr;
One key advantage to this approach is performance. Databases tend to do a poor job when joins are on expression or or conditions.

Oracle PL/SQL: referencing to a column name in inner joined query

I have the following SQL statement:
SELECT *
FROM cars car
LEFT JOIN (SELECT *
FROM cars auto
LEFT JOIN steeringwheels sw
ON auto.steeringwheelid = sw.ID
WHERE material = 'leather') innertable
ON innertable.ID = car.ID
LEFT JOIN steeringwheels sw
ON auto.steeringwheelid = sw.ID
WHERE sw.material='plastic'
This query delivers the columns from the table "Cars" twice, but with different values for the ID from the Car table (the purpose of the query is to map the values to see what the Car.ID would be id the material would change from leather to plastic).
------------------------------------
| ID | material | ID_1 | material_1 |
-------------------------------------
| 1 | leather | 4 | plastic |
| 2 | leather | 7 | plastic |
-------------------------------------
However, I would like to output only the ID columns (not the material columns), like this:
-------------
| ID | ID_1 |
-------------
| 1 | 4 |
| 2 | 7 |
-------------
I have not been able to do this, as I haven't found a way to refer to the ID column of the inner query in any way. For example
SELECT id, innertable.id
(...)
or
SELECT id, auto.id
(...)
or
SELECT id, id_1
(...)
don't seem to work. How can achieve this?
Try explicitly listing the column names of the inner table in the select statement. Like:
...(SELECT auto.ID autoid, auto.Whatever)....
and then in the main select:
SELECT innertable.autoid ....
Is this what you're after?
SELECT auto_id, steeringwheel_id
FROM cars car
LEFT JOIN (SELECT auto.ID AS auto_id, sw1.id AS steeringwheel_id
FROM cars auto
LEFT JOIN steeringwheels sw1
ON auto.steeringwheelid = sw1.ID
WHERE material = 'leather') innertable
ON innertable.auto_ID = car.ID
LEFT JOIN steeringwheels sw2
ON auto.steeringwheelid = sw2.ID
WHERE sw.material='plastic'