SQL Join with 3 Tables and WHERE - sql

i finish off make this exercise but i wanna more opinion about this final result, if you make other way or tips to improve me current code.
This picture abelow is the explanation about this question.
-- create a table
CREATE TABLE supplier (
SUPPLIER_CODE TEXT PRIMARY KEY,
SUPPLIER_NAME TEXT NOT NULL,
CITY TEXT NOT NULL
);
CREATE TABLE part (
CODE_PART TEXT PRIMARY KEY,
NAME_PART TEXT NOT NULL,
PRICE TEXT NOT NULL
);
CREATE TABLE car (
CODE_CAR TEXT PRIMARY KEY,
NAME_CAR TEXT NOT NULL,
TYPE TEXT NOT NULL
);
CREATE TABLE supply (
CODE_SUPPLIER TEXT PRIMARY KEY,
CODE_PIECE TEXT NOT NULL,
CODE_CAR TEXT NOT NULL
);
INSERT INTO supplier VALUES ('S1', 'Auto peças', 'Camacan');
INSERT INTO supplier VALUES ('S2', 'Peças FTX', 'VITORIA');
INSERT INTO supplier VALUES ('S3', 'Importados AUTO', 'VITORIA');
INSERT INTO part VALUES ('P1', 'MOTOR', '1000');
INSERT INTO part VALUES ('P2', 'VELA', '1500');
INSERT INTO part VALUES ('P3', 'MOTOR', '3000');
INSERT INTO car VALUES ('C1', 'KOMBI', 'HATCH');
INSERT INTO car VALUES ('C2', 'FUSCA', 'HATCH');
INSERT INTO car VALUES ('C3', 'KOMBI', 'HATCH');
INSERT INTO supply VALUES ('S1', 'P2', 'C2');
INSERT INTO supply VALUES ('S2', 'P1', 'C1');
INSERT INTO supply VALUES ('S3', 'P3', 'C3');
-- fetch some values
SELECT supplier.SUPPLIER_NAME, part.PRICE
FROM supplier INNER JOIN supply, part, car ON supply.CODE_SUPPLIER = supplier.SUPPLIER_CODE AND supply.CODE_PIECE = part.CODE_PART AND supply.CODE_CAR = car.CODE_CAR
WHERE (supplier.CITY='VITORIA' AND part.NAME_PART='MOTOR' AND car.NAME_CAR='KOMBI' );
Final result
Peças FTX|1000
Importados AUTO|3000
I use the website, https://www.mycompiler.io/new/sql to test my sql.

Your SQL functions correctly in SQLite.
One critique of your query: You use a combination of JOIN and the old-school supply, part, car comma join syntax. It's far clearer, at least to 21st-century data people, to use JOIN syntax throughout. And, if you have to change things to use a LEFT JOIN later, it's less error prone. And, it doesn't port to most other database server makes.
One style thing: Be fanatic about formatting your queries to be readable. One long line: not readable. It's important to be able to read and reason about queries, and formatting helps a lot. It's important for yourself a year from now, and for colleagues.
Here is my rewrite of your query to match my suggestions.
SELECT supplier.SUPPLIER_NAME, part.PRICE
FROM supplier
INNER JOIN supply ON supply.CODE_SUPPLIER = supplier.SUPPLIER_CODE
INNER JOIN part ON supply.CODE_PIECE = part.CODE_PART
INNER JOIN car ON supply.CODE_CAR = car.CODE_CAR
WHERE supplier.CITY='VITORIA'
AND part.NAME_PART='MOTOR'
AND car.NAME_CAR='KOMBI';

Related

Select from a list in a parameter value

I am trying to have a dropdown with subject areas for a school report. The problem I am running into is that in my database, the subjects are grouped by grade and subject instead of just subject. So when I look at gt.standardid in (#SubjectArea) for "Literacy" the standard ids for literacy are (54,61,68,75,88,235) one for each grade level, but I want to have it show me all of them as Literacy. In my parameter "#subjectArea" I have specific values I want to add for each subject area, so for the Label of "Literacy" I want it to select the StandardIds (54,61,68,75,88,235). I am not sure how to accomplish this.
Select
CS.subjectArea
,CS.Name As Group_Name
,GT.Abbreviation
,GT.Name
,GT.standardID
From GradingTask as GT
inner join CurriculumStandard CS
on GT.Standardid = CS.standardid
where GT.ARCHIVED = 0
and GT.standardid in (#SubjectArea)
ORDER BY GT.seq
I would try a cascading parameter approach.
You can have the first parameter be a pre-defined list:
The specific values are not important, but will be used in the next step.
Ideally your IDs would be in a table already, but if not you can use something like this:
declare #SubjectIDs as table
(
[SubjectName] nvarchar(50),
[SubjectID] int
);
insert into #SubjectIDs
(
[SubjectName],
[SubjectID]
)
values
('Literacy', 54),
('Literacy', 61),
('Literacy', 68),
('Literacy', 75),
('Literacy', 88),
('Literacy', 23);
select
SubjectID
from #SubjectIDs
where SubjectName in (#SubjectList);
Make this into a data set. I'm going to call it DS_SubjectIDs.
Make a new hidden or internal parameter called SubjectIDs:
Set it to get its values from the DS_SubjectIDs query:
You can now use the parameter for SubjectIDs in your final query.

Join with json column?

I need find rows in table users by joining column in table queries.
I wrote some sql but it takes 0.200s to run, when SELECT * FROM ... takes 0.80s.
How can I improve performance?
db-fiddle example
The tables are :
CREATE TABLE users (
id INT,
browser varchar
);
CREATE TABLE queries (
id INT,
settings jsonb
);
INSERT INTO users (id,browser) VALUES (1, 'yandex');
INSERT INTO users (id, browser) VALUES (2, 'google');
INSERT INTO users (id, browser) VALUES (3, 'google');
INSERT INTO queries (id, settings) VALUES (1, '{"browser":["Yandex", "TestBrowser"]}');
and the query :
select x2.id as user_id, x1.id as query_id
FROM (
SELECT id, json_array_elements_text((settings->>'browser')::JSON) browser
FROM queries) x1
JOIN users x2 ON lower(x1.browser::varchar) = lower(x2.browser::varchar)
group by 1,2;
json_array_elements_text((settings->>'browser')::JSON)
'->>' converts the result to text. Then you cast it back to JSON. Doing that on one row (if you only have one) is not really going to be a problem, but it is rather pointless.
You could instead do:
jsonb_array_elements_text(settings->'browser')
ON lower(x1.browser::varchar) = lower(x2.browser::varchar)
You can create an index that can be used for this:
create index on users (lower(browser));
It won't do much good on a table with 3 rows. But presumably you don't really have 3 rows.

How to handle a range within a data field

I have a set of data with ranges of numbers that are saved to the field itself. So for example, in the age column there are entries like "60-64", "65+" and in the income field "30\,000-40\,000". Is there a way to query these fields and treat them as number ranges? So a query for 52500 would match the "50\,000-60\,000" income range?
Preprocessing the input is my current top idea, where I just map the user input to all possible values for these fields before I query the database. But I was wondering if there is a better way.
Assume that I cannot modify the database or create a new database at all.
There is no easy way with SQLite that I know off, and you certainly would be better off to restructure all your range columns into two columns each, range_start and range_end.
If your ranges are fixed ranges, you can get the minimum / maximum from a separate table:
create table age_ranges (
name varchar(16) unique not null
, range_start integer unique not null
, range_end integer unique not null
);
insert into age_ranges (name, range_start,range_end) values ('60-64',60,64);
insert into age_ranges (name, range_start,range_end) values ('65+',65,999);
create table participant (
name varchar(16) unique not null
, age integer not null
, income integer not null
);
insert into participant (name, age, income) values ('Joe Blow', 65, 900);
insert into participant (name, age, income) values ('Jane Doe' , 61 , 1900)
;
create table question (
question varchar(64) not null
, relevant_age varchar(32) not null
);
insert into question (question,relevant_age) values('What is your favourite non-beige color?', '65+');
insert into question (question,relevant_age) values('What is your favourite car?', '60-64');
;
select
p.name,
q.question,
q.relevant_age
from participant p
join age_ranges r on (r.range_start <= p.age and p.age <= r.range_end)
join question q on q.relevant_age = r.name
SQL Fiddle
Alternatively, you can also try to parse the range start and range end out by using string functions such as LEFT() etc., but the performance will likely bad.

How do NOT EXISTS and correlated subqueries work internally

I would like to understand how NOT EXISTS works in a correlated subquery.
In this query, it's returned the patient that takes all the medications, but I don't understand why.
Could someone please explain what's happening in each step of execution of this query and which records are being considered and dismissed in each step.
create table medication
(
idmedic INT PRIMARY KEY,
name VARCHAR(20),
dosage NUMERIC(8,2)
);
create table patient
(
idpac INT PRIMARY KEY,
name VARCHAR(20)
);
create table prescription
(
idpac INT,
idmedic INT,
date DATE,
time TIME,
FOREIGN KEY (idpac) REFERENCES patient(idpac),
FOREIGN KEY (idmedic) REFERENCES medication(idmedic)
);
insert into patient (idpac, name)
values (1, 'joe'), (2, 'tod'), (3, 'ric');
insert into medication (idmedic, name, dosage)
values (1, 'tilenol', 0.01), (2, 'omega3', 0.02);
insert into prescription (idpac, idmedic, date, time)
values (1, 1, '2018-01-01', '20:00'), (1, 2, '2018-01-01', '20:00'),
(2, 2, '2018-01-01', '20:00');
select
pa.name
from
patient pa
where
not exists (select 1 from medication me
where not exists (select 1
from prescription pr
where pr.idpac = pa.idpac
and pr.idmedic = me.idmedic))
Your query is trying to find:
all the patients who TAKE ALL medications.
I have rewritten your script, to find
all the patients who have NOT TAKEN ANY medications.
-- This returns 1 Row, patient ric
-- all the patients who take all medications
select
pa.name
from
patient pa
where
not exists (select 1 from medication me
where /**** not ****/ exists (select 1
from prescription pr
where pr.idpac = pa.idpac
and pr.idmedic = me.idmedic))
DEMO:
Here is a SQL Fiddle for it.
I think that this query will clarify the usage of EXISTS operator to you.
If not, try to think of sub-queries as JOINs and EXISTS/NOT EXISTS as WHERE conditions.
EXISTS operator is explained as "Specifies a subquery to test for the existence of rows".
You could also check the examples on learn.microsoft.com Here.
If you see a doubly nested "not exists" in a query that's usually an indication that relational division is being performed (google that, you'll find plenty of stuff).
Translating the query clause by clause into informal language yields something like :
get patients
for which there does not exist
a medication
for which there does not exist
a prescription for that patient to take that medication
which translates to
patients for which there is no medication they don't take.
which translates to
patients that take all medications.
Relational division is the relational algebra operator that corresponds to universal quantification in predicate logic.

SQL INSERT statement for TWO TABLES at time with INNER JOIN

I have two tables hello and login_table and below is their structure
user_info
-------
some_id | name | address
login_table
-------
id | username | password
some_id and id are autoincrement indexes.
Now how can i use INSERT statement with INNER JOIN in SQL
at present, i want add below data with same some_id and id
`name` = John
`address` = wall street
`username` = john123
`password` = passw123
below code shows, what i have tried so far.
insert into login_table lt
INNER JOIN user_info ui ON ui.some_id = lt.id
(ui.name, ui.address, lt.username, lt.password)
values
('John', 'wall street', 'john123', 'passw123')
And this is not the one value, i want to add more than one value at a time.. how can i achieve.
thanks for help.
If you need to perform the two INSERT operations atomically, use a transaction:
START TRANSACTION;
INSERT INTO login_table (username, password) VALUES ('john123', 'passw123');
INSERT INTO user_info (name, address) VALUES ('John', 'wall street');
COMMIT;
N.B. Your storage engine must support transactions for this to work (e.g. InnoDB).
To insert multiple values into a table at once, use the multiple rows form of INSERT. As stated in the manual:
INSERT statements that use VALUES syntax can insert multiple rows. To do this, include multiple lists of column values, each enclosed within parentheses and separated by commas. Example:
INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);
The values list for each row must be enclosed within parentheses. The following statement is illegal because the number of values in the list does not match the number of column names:
INSERT INTO tbl_name (a,b,c) VALUES(1,2,3,4,5,6,7,8,9);
VALUE is a synonym for VALUES in this context. Neither implies anything about the number of values lists, and either may be used whether there is a single values list or multiple lists.
Insert to two tables is impossible. The second part of your question is possible: you can insert multiple rows in one statement like this:
insert into some_table(col1, col2) values (1,2), (3,4), (5,6);
USE [ERPDb]
GO
INSERT INTO [AAA].[UserRole] ([UserId], [RoleId])
SELECT u.Id, (SELECT Id FROM [AAA].[Role] WHERE Title = 'Employee') FROM [AAA].[User] u
INNER JOIN [dbo].[BaseDealer] bd ON u.Id = bd.Id
WHERE bd.DealerType = 0
GO