SQL Logic or Query to find what is missing - sql

Hi all I need your help on the following logic. Currently I have a table that has 300 records, that are related but on this new tables I have the columns called them country, POS so for each combination of country + POs I should have 1 record of table A.
but the situation is that when I am checking the last table someone only inserted some records of table A into table b, and now I have to find what are the missing combination.
could you guide me on the logic that I should use for this, any question please let me know.
Example
Table A name Categories
Milk
Hot Sauces
Meat
Table B
Category POS Country
Milk DF Mexico
Meat DF Mexico
Hot Sauces DF Mexico
Milk CC Canada
Like you can see Canada still missing 2 categories but this table have all Americas countries so let say I have 20 countries. So 20 multiple by 300 categories I should have 6000 distinct records or more because each country have different quantities of POS, right, but someone only inserted let say 3600 records so now I have to find what combination are missed.

If you Don't have a country table you can derive one by selecting DISTINCT Country from your TableB. Then cross join that with Categories for a Cartesian Join (all possible combinations) between Countries and Categories.
SELECT countries.country, c.Category
FROM
(SELECT DISTINCT Country
FROM
#TableB) as countries
CROSS JOIN #Categories c
LEFT JOIN #TableB b
ON countries.Country = b.Country
AND c.Category = b.Cateogry
WHERE
b.Cateogry IS NULL
If you actually need All Possible Combinations of POS and Country and Categories. In this case it sounds like POS is more like a store than a point of sale but same concept. Just derive a POS table if you don't have one and cross join it with the cross join of countries and categories.
SELECT
countries.country, c.Category, pos.POS
FROM
(SELECT DISTINCT Country
FROM
#TableB) as countries
CROSS JOIN #Categories c
CROSS JOIN (SELECT DISTINCT POS
FROM
#TableB) as pos
LEFT JOIN #TableB b
ON countries.Country = b.Country
AND c.Category = b.Cateogry
AND pos.POS = b.POS
WHERE
b.Cateogry IS NULL
But I would guess that not every store is in every country so you probably want to constrain the POS combiantions to POS's that are available in a particular country. Again you can derive the table if you don't have one this time include Country and do an inner join between the derived country table and it.
SELECT
countries.country, c.Category, pos.POS
FROM
(SELECT DISTINCT Country
FROM
#TableB) as countries
CROSS JOIN #Categories c
INNER JOIN (SELECT DISTINCT Country, POS
FROM
#TableB) as pos
ON countries.Country = pos.Country
LEFT JOIN #TableB b
ON countries.Country = b.Country
AND c.Category = b.Cateogry
AND pos.POS = b.POS
WHERE
b.Cateogry IS NULL
test data used:
DECLARE #Categories AS TABLE (Category VARCHAR(25))
DECLARE #TableB AS TABLE (Cateogry VARCHAR(25),POS CHAR(2), Country VARCHAR(25))
INSERT INTO #Categories VALUES ('Milk'),('Hot Sauces'),('Meat')
INSERT INTO #TableB VALUES ('Milk','DF','Mexico'),('Meat','DF','Mexico'),('Hot Sauces','DF','Mexico'),('Milk','CC','Canada'),('Milk','XX','Canada')

Hi, You can use below logic to get missing data,
SELECT column_name FROM tableA WHERE column_name NOT IN
(SELECT column_name FROM tableB)
Change the required column names and table names in the query. Use same column names in all three places

Related

SQL joining columns of the same table

I need help on the following SQL query. Let's say we have table_1 with these columns:
number
Customer
list
321
4514
321
2
2
5321
2
5555
If there's a number in the list column, that indicates that is that there is a list of numbers that should refer to that list. Below is a snapshot of how the final table should look. When there's a null value in the customer field it indicates that there is a list, that list number you can find the customers on that list when the number = the list. I need to change the number to make reference to the number the list belongs to.
number
Customer
list
321
4514
321
5321
2
321
5555
2
I've tried with different joins but unsuccessful:
SELECT *
FROM table_1
OUTER JOIN
(SELECT *
FROM TABLE_1
WHERE list IS NOT NULL) AS table_2 ON TABLE_1.list = table_2.list
You say that this is guaranteed to be one level only. So you can have 321->2, but not, say, 321->2->1.
Then, well, let's join and show the joined result:
select
coalesce(ref.number, t1.number) as num,
t1.customer,
ref.list
from table_1 t1
left outer join table_1 ref on ref.list = t1.number
where t1.list is null;
I guess you need to change the data (DML). Here us an example:
DROP TABLE IF EXISTS customer_list
CREATE TABLE customer_list (
number INT,
Customer INT,
list INT
);
INSERT INTO customer_list (number, Customer, list)
VALUES
(321, 4514, NULL),
(321, NULL, 2),
(2, 5321, NULL),
(2, 5555, NULL);
UPDATE A
SET [number] = B.number
,[list] = b.list
FROM customer_list A
INNER JOIN customer_list B
ON A.number = B.list
WHERE B.Customer IS NULL
DELETE FROM customer_list
WHERE Customer IS NULL;
SELECT *
FROM customer_list
If you need only to get the records:
SELECT B.number
,A.customer
,B.List
FROM customer_list A
INNER JOIN customer_list B
ON A.number = B.list
WHERE B.Customer IS NULL

SQL query - Return 0 for the column if no record found

I will like to see the specific fields returns with 0 value when there is no record found.
Below are my SQL queries that I have tried so far.
SELECT Customer, Address, Number of lines, Date
FROM table_name
WHERE Date = '30-5-2022' AND Customer IN (A, B, C)
What it returns is only 1 row as below.
Customer
Address
Number of Lines
Date
A
3
RF
30-5-2022
But what I expected to see is:
Customer
Address
Number of Lines
Date
A
UK
33
30-5-2022
B
0
0
30-5-2022
C
0
0
30-5-2022
The customer B and C has no record on 30-5-2022 but I will still need to see the rows but certain columns can be 0.
Please advise if anything that I have missed out? Thanks a lot!
Try below query:
SELECT A.Customer, ISNULL(B.Address, 0),
ISNULL(B.[Number of lines],0), ISNULL(B.Date, '30-05-2022') Date
FROM
(
SELECT DISTINCT Customer
FROM table_name
) A
LEFT JOIN table_name B
ON A.Customer = B.Customer
AND B.Date = '30-5-2022'
This will output all the customers present in the table. You can filter the customers with WHERE clause in the end of the above query based on your requirement.
dbfiddle Link
Assuming customers are in one table (cust) and other stuff in another table (table_name) and they are connected with an id called custid, you need some sweet, sweet left join action, such as:
SELECT c.Customer, c.Address, isnull([Number of lines],0), d.Date
FROM cust c left join table_name d on c.custid = d.custid and
d.Date = '30-5-2022' where
c.Customer IN ('A', 'B', 'C')
You need to put A, B, C in a table and left-join the main table to it. All other conditions must then go in the ON clause not the WHERE.
You can use a virtual VALUES clause for this
SELECT Customer, Address, Number of lines, Date
FROM (VALUES
('A'),
('B'),
('C')
) v(Customer)
LEFT JOIN table_name tn ON tn.Customer = v.Customer
AND tn.Date = '30-5-2022';
Alternatively you can pass in a Table Valued Parameter, or use a table variable. Don't forget to add a primary key.
DECLARE #tmp TABLE (Customer varchar(100) PRIMARY KEY);
INSERT #tmp(Customer) VALUES
('A'),
('B'),
('C');
SELECT Customer, Address, Number of lines, Date
FROM #tmp v
LEFT JOIN table_name tn ON tn.Customer = v.Customer
AND tn.Date = '30-5-2022';

How to select all dishes containing a list of ingredients

I am looking to build a query which would return the dishes that contain a list of ingredients but I can't figure it out. The dish returned must contain at least the list of ingredients requested.
Ingredients
============
ID
IngredientName
IngredientAmount
P_ID
Dishes
==========
ID
DishName
DishIngredients
==========
ID
DishID
IngredientID
So far I built the following query, but it returns all meals that contain at least 1 of the ingredients in the list, not only those which contain all ingredients in the list.
The list of ingredients to match is a string converted to a table because I want to use it as an argument in a stored procedure.
DECLARE #IdIngredients nvarchar(1024) = '4174, 4028'
DECLARE #Ingredients TABLE (IdIngredient int)
INSERT #Ingredients (IdIngredient)
SELECT Convert(int, value) FROM STRING_SPLIT(#IdIngredients, ',')
SELECT DISTINCT D.Id
FROM Dishes D
INNER JOIN DishIngredients DI ON DI.DishID = D.ID
WHERE IngredientID IN (SELECT IdIngredient FROM #Ingredients)
Any help would be welcome. I am sure there is a way to manage it either with a join or by counting matching ingredients, but I can't figure it out.
While writing this post, I maybe found a solution but I still need to test it:
DECLARE #IdIngredients nvarchar(1024) = '4174, 4028'
DECLARE #Ingredients TABLE (IdIngredient int)
INSERT #Ingredients (IdIngredient)
SELECT Convert(int, value) FROM STRING_SPLIT(#IdIngredients, ',')
SELECT DISTINCT D.Id
FROM Dishes D
INNER JOIN DishIngredients DI ON DI.DishID = D.ID
WHERE IngredientID IN (SELECT IdIngredient FROM #Ingredients)
GROUP BY D.Id
HAVING COUNT(D.Id) = (SELECT COUNT(*) FROM #Ingredients)
A double NOT EXISTS should do the trick:
SELECT D.*
FROM Dishes As D
WHERE Not Exists
(
SELECT 1
FROM #Ingredients As I
WHERE Not Exists
(
SELECT 1
FROM DishIngredients As DI
WHERE DI.DishID = D.Id
And DI.IngedientId = I.IdIngredient
)
)
Or, if you'd prefer, a NOT EXISTS with an EXCEPT:
SELECT D.*
FROM Dishes As D
WHERE Not Exists
(
SELECT IdIngredient
FROM #Ingredients
EXCEPT
SELECT IngredientId
FROM DishIngredients As DI
WHERE DI.DishID = D.Id
)
EXCEPT and INTERSECT (Transact-SQL) - SQL Server | Microsoft Docs
So far I buit following query but it returns all meals that contain at least 1 of the ingredients in the list but not only those which contain all ingredients in the list.
When you split the ingredients list, you can gather how many ingredients there are. Let it be X.
Now if you join the dishes with the recipes,
SELECT D.*, COUNT(*) AS N
FROM Dishes As D
JOIN DishIngredients AS DI ON (DI.DishID = D.ID)
JOIN Ingredients AS I ON (I.ID = DI.IngredientID)
WHERE Ingredients.IngredientName IN (#IngredientNameList)
GROUP BY D.ID
it will report, for each dish, how many ingredients there are from the supplied ingredient list.
The dishes you want are those HAVING N = X.
(If you have the ingredients IDs, even better, you can save yourself the JOIN with Ingredients and use IngredientID instead).

SQL Multiple Joins Query

Here I have two tables committee_colleges and colleges.
Structure of tables is something like this
committee_colleges
committeeCollegeId collegeId committeeMemberId
1 2 1
2 2 2
3 3 2
I am storing committeeMemberId from committeeMember table.And one college can have multiple committee Members.How can I wite a query to display only the colleges assigned to specific committee Member.
For Example,if committeeMember by id=2 has logged in I want to display colleges by id=2,3.
In college table I have like this,
collegeId typeName
1 AICTE
2 NCTE
3 NTCS
This is Committee Member table
committeeMemberId name
1 xyz
2 abc
Now I am writing something like this,but i know its wrong because I dont know how to take it from College table since I am displaying College details.
SELECT cc.committeeCollegeId as committeeCollegeId,
c.collegeId as collegeId,
cc.committeeMemberId as committeeMemberId
FROM committee_college as cc
left outer join College as c
on cc.collegeId = c.collegeId
where cc.committeeMemberId=:committeeMemberId
order by cc.committeeCollegeId asc
Can anyone tell how to display colleges based on its assignment to particular committeeMember?
You were close, you need INNER JOIN instead of LEFT JOIN:
SELECT DISTINCT C.typeName --<<== put here all the columns that you want in output
FROM committee_colleges CC
INNER JOIN college C
ON C.collegeId = CC.collegeId
WHERE CC.committeeMemberId = 2 --<<== your input parameter
EDIT: added DISTINCT
Hope it helps.
You can use below sql statement for the same
DECLARE #committeeMemberId INT = 2 -- Id of Committee member
;WITH CTE_MemberCommittee AS
(
SELECT CollegeId
FROM committee_colleges
WHERE committeeMemberId = #committeeMemberId
)
SELECT collegeId, typeName
FROM college
WHERE collegeId IN (SELECT CollegeId FROM CTE_MemberCommittee)
You can use simple inner join for that,
If you want collegename based on memberId use following query,
select a.collegeid,a.typeName from
college a, committee_colleges b, committe_member c
where a.collegeid = b.collegeid and
b.committeememberid = c.committeeMemberId
and c.committeeMemberId = '2'
If you want collegename based on committemember name then use following query,
select a.collegeid,a.typeName from
college a, committee_colleges b, committe_member c
where a.collegeid = b.collegeid and
b.committeememberid = c.committeeMemberId
and c.Name = 'xyz'
Hope it will help.
try this:
DECLARE #LoginCommitteeMemberId INT=2
SELECT t2.Name AS MemberName,
t3.TypeName AS CollageName
FROM committee_college t1
INNER JOIN Committee_Member t2
ON t1.committeeMemberId = t2.committeeMemberId
INNER JOIN College as t3
ON t1.collegeId = t3.collegeId
WHERE t1.committeeMemberId = #LoginCommitteeMemberId

Select persons which have overlap with other table

I didn't even know how to come up with a good title, so I hope I can describe my problem in a right way :)
So I have a person table, and it has a N:N relationship with keywords via the table PersonKeywords.
Then I also have a Search table, and it also has a N:N relationship with keywords via the table SearchKeywords.
Now the person can have a relationship with keyword A and B, and the search record can have a relationship with the keywords A and C.
Now I want the person in my resultset, because it has at least one (in this 'A') of the keywords the search record has.
I also want the person who has 'A', the one with 'C', the one with 'A' and 'C', but not the one with only B.
So it's a match on two lists, but I don't know where to start to create such a statement...
So you have three people...
declare #persons table (id int identity(1,1), name varchar(10))
insert #persons (name) values ('Babs'),('Ken'),('Neville'),('Sue')
Babs has A and B, Ken has A and C, Neville has B only and Sue has C only
declare #personkeywords table (personid int, keyword varchar(5))
insert #personkeywords values (1,'a'),(1,'b'),(2,'a'),(2,'c'),(3,'b'),(4,'c')
The search is for A or C
declare #searchkeywords table (searchid int, keyword varchar(5))
insert #searchkeywords values (1,'a'),(1,'c')
So...
select distinct persons.*
from #persons persons
inner join #personkeywords personkeywords on persons.id = personkeywords.personid
inner join #searchkeywords searchkeywords on personkeywords.keyword = searchkeywords.keyword
where
searchkeywords.searchid = 1
Gives
1 Babs
2 Ken
4 Sue
Although I don't have very much information to work with, the following should at least help you...
SELECT s.SearchID, k.Keyword, p.PersonID, p.Name
FROM Search s
INNER JOIN SearchKeywords sk ON s.SearchID = sk.SearchID
INNER JOIN Keywords k ON sk.KeywordID = k.KeywordID
LEFT OUTER JOIN PersonKeywords pk ON k.KeywordID = pk.KeywordID
LEFT OUTER JOIN Person p ON pk.PersonID = p.PersonID
WHERE k.Keyword = 'mykeyword'
GROUP BY s.SearchID, k.Keyword, p.PersonID, p.Name