SQL inner join condition by actual date - sql

I need to join actual document to people. Documents has date issued (passport, for example).
SQL Fiddle: http://sqlfiddle.com/#!9/3a8118/2/0
Table structure:
CREATE TABLE people
(
p_id INT NOT NULL AUTO_INCREMENT,
p_name VARCHAR(50) NOT NULL,
PRIMARY KEY(p_id)
);
INSERT INTO people (p_id, p_name)
VALUES (1, 'Name_1'),
(2, 'Name_2');
CREATE TABLE documents
(
d_id INT NOT NULL AUTO_INCREMENT,
d_people INT(10) NOT NULL,
d_date VARCHAR(10) NOT NULL,
PRIMARY KEY(d_id)
);
INSERT INTO documents (d_id, d_people, d_date)
VALUES (1, 1, '01.01.2022'),
(2, 2, '01.12.2021'),
(3, 1, '05.02.2022'),
(4, 1, '10.02.2022'),
(5, 2, '04.01.2022'),
(6, 1, '20.01.2022');
Query: condition is select actual document when date is 21.01.2022, it must return d_id = 6:
SELECT *
FROM people
INNER JOIN documents ON d_people = p_id
WHERE p_id = 1 AND ??? d_date 21.01.2022 ???
;
I need to do an inner join to return only this row:

use this query:
Fiddle
SELECT * FROM people
INNER JOIN documents ON d_people = p_id
WHERE p_id = 1 and d_date='20.01.2022';

Related

Join operations in SQL

I should retrieve the IDs and names of ingredients that are not contained by any ice cream and then
sort the output rows in ascending order by ingredient ID. I don't quite understand how JOIN -operation works in this exercise.
I tried e.g. the following but it gives too many rows in the output.
SELECT ingredient.ingredient_id, ingredient.ingredient_name
FROM ingredient
LEFT JOIN contains ON ingredient.ingredient_id != contains.ingredient_id
LEFT JOIN ice_cream ON ice_cream.ice_cream_id != contains.ice_cream_id
ORDER BY ingredient.ingredient_id;
Output columns should be as follows:
ingredient_id ingredient_name
----------------------------
6 Dark chocolate
and here are the tables:
CREATE TABLE manufacturer (
manufacturer_id INT,
manufacturer_name VARCHAR(30) NOT NULL,
country VARCHAR(30) NOT NULL,
PRIMARY KEY (manufacturer_id),
UNIQUE (manufacturer_name)
);
-- jäätelöitä
-- ice creams
CREATE TABLE ice_cream (
ice_cream_id INT,
ice_cream_name VARCHAR(30) NOT NULL,
manufacturer_id INT NOT NULL,
manufacturing_cost NUMERIC(4,2),
PRIMARY KEY (ice_cream_id),
UNIQUE (ice_cream_name),
FOREIGN KEY (manufacturer_id) REFERENCES manufacturer
);
-- aineksia
-- ingredients
-- plant_based arvo 0 merkitse ei ja arvo 1 merkitsee kyllä
-- plant_based value 0 means no and value 1 means yes
CREATE TABLE ingredient (
ingredient_id INT,
ingredient_name VARCHAR(30) NOT NULL,
kcal INT,
protein NUMERIC(3,1),
plant_based INT,
PRIMARY KEY (ingredient_id),
UNIQUE (ingredient_name)
);
-- jäätelöt sisältävät aineksia
-- ice creams contain ingredients
CREATE TABLE contains(
ice_cream_id INT NOT NULL,
ingredient_id INT NOT NULL,
quantity INT,
PRIMARY KEY (ice_cream_id, ingredient_id),
FOREIGN KEY (ice_cream_id) REFERENCES ice_cream,
FOREIGN KEY (ingredient_id) REFERENCES ingredient
);
--Ice cream manufacturers
INSERT INTO manufacturer VALUES (
1, 'Jen & Berry', 'Canada'
);
INSERT INTO manufacturer VALUES (
2, '4 Friends', 'Finland'
);
INSERT INTO manufacturer VALUES (
3, 'Gelatron', 'Italy'
);
--Ice cream
INSERT INTO ice_cream VALUES (
1, 'Plain Vanilla', 1, 1.00
);
INSERT INTO ice_cream VALUES (
2, 'Vegan Vanilla', 2, 0.89
);
INSERT INTO ice_cream VALUES (
3, 'Super Strawberry', 2, 1.44
);
INSERT INTO ice_cream VALUES (
4, 'Very plain', 2, 1.20
);
--Ingredients
INSERT INTO ingredient VALUES (
1, 'Cream', 400, 3, 0
);
INSERT INTO ingredient VALUES (
2, 'Coconut cream', 230, 2.3, 1
);
INSERT INTO ingredient VALUES (
3, 'Sugar', 387, 0, 1
);
INSERT INTO ingredient VALUES (
4, 'Vanilla extract', 12, 0, 1
);
INSERT INTO ingredient VALUES (
5, 'Strawberry', 33, 0.7, 1
);
INSERT INTO ingredient VALUES (
6, 'Dark chocolate', 535, 8, 1
);
--Contains
INSERT INTO contains VALUES (
1, 1, 70
);
INSERT INTO contains VALUES (
1, 3, 27
);
INSERT INTO contains VALUES (
1, 4, 3
);
INSERT INTO contains VALUES (
2, 2, 74
);
INSERT INTO contains VALUES (
2, 3, 21
);
INSERT INTO contains VALUES (
2, 4, 5
);
INSERT INTO contains VALUES (
3, 1, 60
);
INSERT INTO contains VALUES (
3, 3, 10
);
INSERT INTO contains VALUES (
3, 5, 30
);
INSERT INTO contains VALUES (
4, 2, 95
);
INSERT INTO contains VALUES (
4, 4, 5
);
You can join the "contains" table with the "ingredient" table using a LEFT JOIN and filter all values that have NULL in the "contains.ice_cream_id" field:
SELECT i.ingredient_id,
i.ingredient_name
FROM ingredient i
LEFT JOIN contains c
ON i.ingredient_id = c.ingredient_id
WHERE c.ice_cream_id IS NULL
It appears you are asking to find where somethig does not exist, so it would make sense to express that using not exists
So you just need to find the ingredients that don't exist in the list of contents:
select ingredient_id, ingredient_name
from ingredient i
where not exists (
select * from contains c
where c.ingredient_id = i.ingredient_id
);
Demo Fiddle

SQL Self Join Update

I need to procedurally update a table by self-joining itself. Using SQL Server 2019.
CREATE TABLE Sect
(
Section_Id INT,
Locale VARCHAR(10),
Record_Id INT,
Section_Id_1 INT
);
INSERT INTO Sect (Section_Id, Locale, Record_Id, Section_Id_1)
VALUES
(100, 'US', 1, Null),
(101, 'CA', Null, 100),
(101, 'MD', Null, 100)
The goal is to update the null values of Record_Id where Section_Id_1 equals Section_ID with the matching Record_ID.
This is the intended result:
100|US|1|Null
101|CA|1|100
101|MD|1|100
I think I am close with:
UPDATE t1
SET Record_Id = t2.Record_Id
FROM Sect t1
INNER JOIN Sect t2 ON t1.Section_Id_1 = t2.Section_Id
WHERE t1.Record_Id IS NULL
Appreciate your all's help.
I'm not familiar with SQL Server 2019. But I think you don't need to use INNER JOIN, try this.
update
Sect t1
set
Record_Id = (select t2.Record_Id
from Sect t2
where t2.Section_ID = t1.Section_Id_1
and t2.Record_Id is not null
limit 1)
where Record_Id is null
and Section_Id_1 is not null

TSQL group by and combine remaining columns in json array

I want to group a result set by a column and combine the remaining columns into a json array, but I'm not sure how to aggregate the results for this.
I want the following output:
A_ID | Translations
--------------------
1 | [{"Name": "english_1","LCID": "en-gb"},{"Name": "french_1","LCID": "fr-fr"}]
2 | [{"Name": "english_2","LCID": "en-gb"},{"Name": "french_2","LCID": "fr-fr"}]
But I cannot group the results by A_ID without an aggregator so I get the following
A_ID | Translations
--------------------
1 | [{"Name": "english_1","LCID": "en-gb"}]
1 | [{"Name": "french_1","LCID": "fr-fr"}]
2 | [{"Name": "english_2","LCID": "en-gb"}]
2 | [{"Name": "french_2","LCID": "fr-fr"}]
Here is an example:
DROP TABLE IF EXISTS #tabA;
DROP TABLE IF EXISTS #tabB;
DROP TABLE IF EXISTS #tabC;
go
CREATE TABLE #tabA
(
Id int not null
);
CREATE TABLE #tabTranslations
(
translationId int not null,
Name nvarchar(32) not null,
aId int not null, -- Foreign key.
languageId int not null --Foreign key
);
CREATE TABLE #tabLanguages
(
languageId int not null,
LCID nvarchar(32) not null
);
go
INSERT INTO #tabA (Id)
VALUES
(1),
(2);
INSERT INTO #tabTranslations (translationId, Name, aId, languageId)
VALUES
(1, 'english_1', 1, 1),
(2, 'french_1', 1, 2),
(3, 'english_2', 2, 1),
(4, 'french_2', 2, 2);
INSERT INTO #tabLanguages (languageId, LCID)
VALUES
(1, 'en-gb'),
(2, 'fr-fr');
go
select
_a.Id as A_ID,
(
select
_translation.Name,
_language.LCID
for json path
)
from #tabA as _a
inner join #tabTranslations as _translation ON _translation.aId = _a.Id
inner join #tabLanguages as _language ON _language.languageId = _translation.languageId
-- group by _a.Id ??
;
go
DROP TABLE IF EXISTS #tabA;
DROP TABLE IF EXISTS #tabTranslations;
DROP TABLE IF EXISTS #tabLanguages;
go
Alternative solution:
I know I can do this, but I obviously don't want to hard code the available LCIDs (maybe I could generate the sql query and exec it? but this feels too complex), also I would prefer an array
select
_a.Id as A_ID,
(
SELECT
MAX(CASE WHEN [LCID] = 'en-gb' THEN [Name] END) 'en-gb',
MAX(CASE WHEN [LCID] = 'fr-fr' THEN [Name] END) 'fr-fr'
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) as b
from #tabA as _a
inner join #tabTranslations as _translation ON _translation.aId = _a.Id
inner join #tabLanguages as _language ON _language.languageId = _translation.languageId
group by _a.Id;
result:
A_ID | Translations
--------------------
1 | { "en-Gb": "english_1", "fr-FR": "french_1"}
2 | { "en-Gb": "english_2", "fr-FR": "french_2"}
If I understand you correctly, next approach may help. Use additional CROSS APPLY operator and FOR JSON PATH to get your expected results:
Statement:
SELECT *
FROM #tabA AS t
CROSS APPLY (
SELECT _translation.Name AS Name, _language.LCID AS LCID
FROM #tabA _a
inner join #tabTranslations as _translation ON _translation.aId = _a.Id
inner join #tabLanguages as _language ON _language.languageId = _translation.languageId
WHERE _a.Id = t.Id
for json path
) _c(Translations)
Output:
Id Translations
1 [{"Name":"english_1","LCID":"en-gb"},{"Name":"french_1","LCID":"fr-fr"}]
2 [{"Name":"english_2","LCID":"en-gb"},{"Name":"french_2","LCID":"fr-fr"}]

SQL Count returns wrong value in my INNER JOIN Statement

I am quite new to SQL and I am having some difficulty with my COUNT() feature.
It keeps returning the wrong COUNT() value as I am trying to calculate the TOTAL number of specific cars sold by users. My tables and results are here:
http://sqlfiddle.com/#!9/d2ef0/5
My Schema:
CREATE TABLE IF NOT EXISTS Users(
userID INT NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
forename VARCHAR(50) NOT NULL,
surname VARCHAR(50) NOT NULL,
PRIMARY KEY (userID)
);
CREATE TABLE IF NOT EXISTS CarType(
carTypeID INT NOT NULL AUTO_INCREMENT,
description VARCHAR(80),
PRIMARY KEY (carTypeID)
);
CREATE TABLE IF NOT EXISTS Country(
countryID INT NOT NULL AUTO_INCREMENT,
name VARCHAR(100),
PRIMARY KEY (countryID)
);
CREATE TABLE IF NOT EXISTS Cars(
carID INT NOT NULL AUTO_INCREMENT,
carTypeID INT NOT NULL,
countryID INT NOT NULL,
description VARCHAR(100) NOT NULL,
make VARCHAR(100) NOT NULL,
model VARCHAR(100),
FOREIGN KEY (carTypeID) REFERENCES CarType(carTypeID),
FOREIGN KEY (countryID) REFERENCES Country(countryID),
PRIMARY KEY (carID)
);
CREATE TABLE IF NOT EXISTS Likes(
userID INT NOT NULL,
carID INT NOT NULL,
likes DOUBLE NOT NULL,
FOREIGN KEY (userID) REFERENCES Users(userID),
FOREIGN KEY (carID) REFERENCES Cars(carID)
);
CREATE TABLE IF NOT EXISTS Sold(
userID INT NOT NULL,
carID INT NOT NULL,
FOREIGN KEY (userID) REFERENCES Users(userID),
FOREIGN KEY (carID) REFERENCES Cars(carID)
);
INSERT INTO Users VALUES
(NULL, "micheal", "Micheal", "Sco"),
(NULL, "bensco", "Ben", "Sco"),
(NULL, "shanemill", "Shane", "Miller");
INSERT INTO CarType VALUES
(NULL, "Saloon"),
(NULL, "HatchBack"),
(NULL, "Low Rider");
INSERT INTO Country VALUES
(NULL, "UK"),
(NULL, "USA"),
(NULL, "JAPAN"),
(NULL, "GERMANY");
INSERT INTO Cars VALUES
(NULL, 1, 2, "Ford Mustang lovers", "Mustang", "Ford"),
(NULL, 2, 3, "Drift Kings", "Skyline", "Nissan"),
(NULL, 3, 1, "British classic", "Cooper", "Mini");
INSERT INTO Likes VALUES
(1, 1, 3),
(1, 2, 2),
(2, 3, 5),
(2, 3, 7),
(2, 3, 1),
(2, 3, 2);
INSERT INTO Sold VALUES
(1, 2),
(1, 3),
(1, 1),
(2, 2),
(2, 3),
(3, 1),
(3, 3);
This is the Sold table:
userID carID
1 2
1 3
1 1
2 2
2 3
3 1
3 3
This is my complex query:
SELECT DISTINCT Cars.carID, Cars.description, Cars.model, Country.name,
CarType.description, ROUND(AVG(Likes.likes)), COUNT(*)
FROM Cars
INNER JOIN Sold ON
Cars.carID = Sold.carID
INNER JOIN Country ON
Cars.countryID = Country.countryID
INNER JOIN CarType ON
Cars.carTypeID = CarType.carTypeID
INNER JOIN Likes ON
Cars.carID = Likes.carID
GROUP BY Cars.carID
The actual result from this complex SQL Query:
carID description model name description ROUND(AVG(Likes.likes)) COUNT(*)
1 Ford Mustang lovers Ford USA Saloon 3 2
2 Drift Kings Nissan JAPAN HatchBack 2 2
3 British classic Mini UK Low Rider 4 12
For example, the result for the last one is incorrect - it should not be 12
Would be nice if someone could tell me where I went wrong
Thanks
You are attempting to aggregate across two different dimensions -- Sold and Likes. The result is a Cartesian product of rows for each car, and this throws off the aggregations.
The solution is the pre-aggregate the results along each dimension:
SELECT c.carID, c.description, c.model, cy.name, ct.description,
l.avgLikes, s.NumSold
FROM Cars c INNER JOIN
(SELECT s.CarId, COUNT(*) as NumSold
FROM Sold s
GROUP BY s.CarId
) s
ON c.carID = s.carID INNER JOIN
Country cy
ON c.countryID = cy.countryID INNER JOIN
CarType ct
ON c.carTypeID = ct.carTypeID LEFT JOIN
(SELECT l.carId, AVG(Likes) as avgLikes
FROM Likes l
GROUP BY CarId
) l
ON c.carID = l.carID;
Here is the SQL Fiddle.
If all you want is the total number of specific cars sold by user then all your info is in the sold table. This query will give you what you want by carID. You can use that as a subquery if you want to join on other tables to get more info.
SELECT userID, carID, count(*) as totalSold FROM Sold GROUP BY userID, carID;

need sql, a tricky one

suppose I have three relations
part(partno,partname,color) partno is P.K
supplier(supplierno,sname) supplierno is P.K
part_supplier(supplierno,partno) supplierno, partno is P.K.
Now i want to get the name of the suppliers who supply parts of only one color.
The having clause is your freind.
select field1, etc, count(*) records
from yourTables
where whatever
group by field1, etc
having count(*) = 1
SELECT s.supplierno
FROM supplier AS s
JOIN part_supplier AS ps
ON s.supplierno = ps.supplierno
JOIN part AS p
ON ps.partno = p.partno
GROUP BY s.supplierno
HAVING COUNT(DISTINCT p.color) = 1 -- only one color for all parts
Select sup.sname,count(*) from part_supplier Map
inner join supplier sup
on map.supplierno=sup.supplierno
inner join part par
on Map.partno=par.partno
group by sup.sname
having count(*)=1
Query:
SELECT S.sname
FROM part P, supplier S, part_supplier PS
WHERE S.supplierno = ps.supplierno AND
PS.partno = P.partno
GROUP BY P.partno
HAVING count(P.color) = 1
Tables :
CREATE TABLE supplier (
supplierno INT PRIMARY KEY,
suppliername VARCHAR(10) NOT NULL
);
CREATE TABLE part (
partno INT PRIMARY KEY,
partname VARCHAR(10) NOT NULL,
color INT NOT NULL
);
CREATE TABLE part_supplier (
supplierno INT NOT NULL REFERENCES supplier(supplierno),
partno INT NOT NULL REFERENCES part(partno),
PRIMARY KEY (supplierno, partno)
);
Some data for testing :
INSERT INTO part VALUES (1, 'a',1), (2, 'b',2), (3, 'c',3),
(4, 'd',1), (5, 'e',2), (6, 'c',3),
(7, 'd',1), (8, 'e',2), (9, 'e',3);
INSERT INTO supplier VALUES (1,'a'), (2,'b'), (3,'c');
INSERT INTO part_supplier VALUES (1,1), (2,1), (3,3),
(4,1), (5,1), (6,1),
(7,2), (8,2), (9,3);