S_id int Primary Key,
S_name varchar(100),
Gpa float ,
Size_hs int
)
Create table Apply (
s_id int ,
C_name varchar(100),
Major varchar(10),
Decision varchar(2)
)
insert into Students values (123,'Amy',3.9,1000)
insert into Students values (234,'Bob',3.6,1500)
insert into Students values (345,'Craig',3.5,500)
insert into Students values (456,'Doug',3.9,1000)
insert into Students values (567,'Edward',2.9,2000)
insert into Students values (678,'Fay',3.8,200)
insert into Students values (789,'Gray',3.4,800)
insert into Students values (987,'Helen',3.7,800)
insert into Students values (876,'Irene',3.9,400)
insert into Students values (765,'Jay',2.9,1500)
insert into Students values (654,'Amy',3.9,1000)
insert into Students values (543,'Craig',3.4,2000)
insert into Apply values (123,'NJIT','CS','Y')
insert into Apply values (123,'NJIT','EE','N')
insert into Apply values (123,'Stoony Brook','CS','Y')
insert into Apply values (123,'Cornell','EE','Y')
insert into Apply values (234,'Stoony Brook','Bio','N')
insert into Apply values (345,'WPI','Bio-Eng','Y')
insert into Apply values (345,'Cornell','Bio-Eng','N')
insert into Apply values (345,'Cornell','CS','Y')
insert into Apply values (345,'Cornell','EE','N')
insert into Apply values (678,'NJIT','Hist','Y')
insert into Apply values (987,'NJIT','CS','Y')
insert into Apply values (987,'Stoony Brook','CS','Y')
insert into Apply values (876,'NJIT','Bio','N')
insert into Apply values (876,'WPI','Marine-Bio','Y')
insert into Apply values (876,'WPI','Hist','N')
insert into Apply values (765,'NJIT','Hist','Y')
insert into Apply values (765,'Cornell','Hist','N')
insert into Apply values (765,'Cornell','Psych','Y')
insert into Apply values (543,'WPI','CS','N')
Create table Students(
S_id int Primary Key,
S_name varchar(100),
Gpa float ,
Size_hs int
)
Create table Apply (
s_id int ,
C_name varchar(100),
Major varchar(10),
Decision varchar(2)
)
insert into Students values (123,'Amy',3.9,1000)
insert into Students values (234,'Bob',3.6,1500)
insert into Students values (345,'Craig',3.5,500)
insert into Students values (456,'Doug',3.9,1000)
insert into Students values (567,'Edward',2.9,2000)
insert into Students values (678,'Fay',3.8,200)
insert into Students values (789,'Gray',3.4,800)
insert into Students values (987,'Helen',3.7,800)
insert into Students values (876,'Irene',3.9,400)
insert into Students values (765,'Jay',2.9,1500)
insert into Students values (654,'Amy',3.9,1000)
insert into Students values (543,'Craig',3.4,2000)
insert into Apply values (123,'NJIT','CS','Y')
insert into Apply values (123,'NJIT','EE','N')
insert into Apply values (123,'Stoony Brook','CS','Y')
insert into Apply values (123,'Cornell','EE','Y')
insert into Apply values (234,'Stoony Brook','Bio','N')
insert into Apply values (345,'WPI','Bio-Eng','Y')
insert into Apply values (345,'Cornell','Bio-Eng','N')
insert into Apply values (345,'Cornell','CS','Y')
insert into Apply values (345,'Cornell','EE','N')
insert into Apply values (678,'NJIT','Hist','Y')
insert into Apply values (987,'NJIT','CS','Y')
insert into Apply values (987,'Stoony Brook','CS','Y')
insert into Apply values (876,'NJIT','Bio','N')
insert into Apply values (876,'WPI','Marine-Bio','Y')
insert into Apply values (876,'WPI','Hist','N')
insert into Apply values (765,'NJIT','Hist','Y')
insert into Apply values (765,'Cornell','Hist','N')
insert into Apply values (765,'Cornell','Psych','Y')
insert into Apply values (543,'WPI','CS','N')
Basically I have to find the list of students id who belongs to major named as 'Cs' but not to the major 'EE'. I tried it by myself but it is not working properly.
Here is the code below:
select * from students
where s_id in (
select s_id
from apply
where major='CS' and Major!='EE'
group by s_id
)```
I would use exists and not exists:
select s.*
from students s
where
exists (select 1 from applies a where a.s_id = s._id and a.major = 'CS')
and not exists (select 1 from applies a where a.s_id = s._id and a.major = 'EE')
With an index on applies(s_id, major), this should be an efficient option.
Another approach is to join, aggregate, and filter with a having clause. This requires listing the columns that you want to show in both the select and group by clauses:
select s.s_id, s.s_name
from students s
inner join applies a on a.s_id = s.s_id
where a.major in ('CS', 'EE')
group by s.s_id, s.s_name
having
max(case when a.major = 'CS' then 1 else 0 end) = 1
and max(case when a.major = 'EE' then 1 else 0 end) = 0
Note: apply is a reserved word in a number a databases (SQL Serer, Oracle, ...), hence not a good choice for a table name. I renamed it to applies in the queries.
I have a table-X with ecode,emp ID ( some values)
37,10
47,20
57,30
There are 2 lookup tables
lookup table 1 has just the emp ID details( which am interested in)
10
20
so when i join..i get all the values needed (thats one part)
my result will be
37 10
47 20
second part is,
the ones which doesnt satisfy the join condition should lookup on table 2 which has
2 columns
ecode, other_codes
37 xxx
47 YYY
57 AAA
So when 30 comes in , i want to return AAA and my final dataset should be,
37, 10
47,20
57 AAA
appreciate any help!
Thanks
You can left join both tables and use CASE statement for selecting a value from one table or the other.
I've created a db-fiddle which I think exemplifies your situation based on your description: https://www.db-fiddle.com/f/ujW8Unf44CqbsiJZXqXXtK/0
Here is the code for posterity. To set up your tables:
CREATE TABLE tableX (
eCode int,
employeeId int
);
INSERT INTO tableX (eCode, employeeId) VALUES (37, 10);
INSERT INTO tableX (eCode, employeeId) VALUES (47, 20);
INSERT INTO tableX (eCode, employeeId) VALUES (57, 30);
CREATE TABLE employeeIds (employeeId int);
INSERT INTO employeeIds (employeeId) VALUES (10);
INSERT INTO employeeIds (employeeId) VALUES (20);
CREATE TABLE otherCodes (
eCode int,
other_codes varchar(10)
);
INSERT INTO otherCodes (eCode, other_codes) VALUES (37, 'XXX');
INSERT INTO otherCodes (eCode, other_codes) VALUES (47, 'YYY');
INSERT INTO otherCodes (eCode, other_codes) VALUES (57, 'AAA');
The query based on this schema:
SELECT
tx.eCode,
CASE WHEN ei.employeeId IS NULL THEN oc.other_codes ELSE ei.employeeId END as 'result'
FROM tableX tx
LEFT JOIN employeeIds ei ON tx.employeeId = ei.employeeId
LEFT JOIN otherCodes oc ON tx.eCode = oc.eCode;
I have the following schema + data:
create table org_users (
id character varying (255),
settings_id character varying (255) -- fk: settings.id
);
create table settings (
id character varying (255), -- primary key settings_id
perdiem_settings character varying (255), -- jsonised fk to perdiems.id
floor_settings character varying (255) -- jsonised fk to floors.id
);
create table perdiems (
id integer, -- primary key
name character varying(255)
);
create table floors (
id integer, -- primary key
name character varying (255)
);
insert into perdiems (id, name) values (1, 'perdiem 1');
insert into perdiems (id, name) values (2, 'perdiem 2');
insert into perdiems (id, name) values (3, 'perdiem 3');
insert into floors (id, name) values (1, 'floor 1');
insert into floors (id, name) values (2, 'floor 2');
insert into floors (id, name) values (3, 'floor 3');
insert into settings (id, perdiem_settings, floor_settings) values ('setting1', '{"allowed_per_diem_ids":[1, 2]}', '{"allowed_floor_ids":[1]}');
insert into settings (id, perdiem_settings, floor_settings) values ('setting2', '{"allowed_per_diem_ids":[2, 3]}', '{"allowed_floor_ids":[1, 2]}');
insert into settings (id, perdiem_settings, floor_settings) values ('setting3', '{"allowed_per_diem_ids":[3, 1]}', '{"allowed_floor_ids":[1, 2, 3]}');
insert into org_users (id, settings_id) values ('user1', 'setting1');
insert into org_users (id, settings_id) values ('user2', 'setting2');
insert into org_users (id, settings_id) values ('user3', 'setting3');
Now I want to create a view which will have aggregates from each of the other table, into an array field of its own. To explain with an example, the view that I want should be like:
org_user_id | settings_id | perdiems | floors
--------------------------------------------------------------------------------------------
user1 | setting1 | ['perdiem 1', 'perdiem 2'] | ['floor 1']
user2 | setting2 | ['perdiem 2', 'perdiem 3'] | ['floor 1', 'floor 2']
user3 | setting3 | ['perdiem 3', 'perdiem 1'] | ['floor 1', 'floor 2', 'floor 3']
This question is somewhat related to postgres aggregate join matches to an array field which deals with creating array fields out of join matches. However, here I want to create multiple array fields in a single view and so using a GROUP BY clause will not be feasible iiuc.
The query that I tried is:
CREATE OR REPLACE VIEW users_settings_view AS
SELECT ou.id AS org_user_id, <other fields...>
FROM org_users ou
LEFT JOIN settings pdr_s ON pdr_s.id = ou.settings_id
LEFT JOIN perdiems pdr ON pdr.id = ANY (SELECT json_array_elements(perdiem_settings::JSON->'allowed_per_diem_ids')::text::int FROM settings)
which creates duplicate records for each of the matching perdiem because of the join and not creating an array. Even if I crate an array as mentioned in the other stackoverflow question, it won't work if I have multiple string arrays as part of the view for different columns. Any way I can get multiple join matches to multiple array fields in a single view ?
This will give you the result.
select ou.id, array_agg( DISTINCT pd.name ),
array_agg( DISTINCT f.name )
from org_users ou join settings s on ou.settings_id = s.id
cross join lateral
json_array_elements_text(((s.perdiem_settings)::json->'allowed_per_diem_ids')::json)
as jp(perdiem) join
perdiems pd
on pd.id = jp.perdiem::int
cross join lateral
json_array_elements_text(((s.floor_settings)::json->'allowed_floor_ids')::json)
as js(floor) join
floors f
on f.id = js.floor::int
GROUP BY ou.id;
Demo
Edit
For cases of NULL settings, you may use a separate UNION ALL
select id , ARRAY[NULL] as perdiems ,ARRAY[NULL] as floors FROM org_users
WHERE settings_id IS NULL
UNION ALL
(
-- The above query --
) ORDER BY id;
Demo2
I have some entities in a table and their attributes and values in an other. I would like to create a select where I can see the value a specific attribute for every entity or null if that attribute is missing. How can I do this using standard SQL?
This is the setup:
create table person (id int not null, nick varchar(32) not null);
insert into person (id, nick) values (1, 'John');
insert into person (id, nick) values (2, 'Peter');
create table req_attributes (name varchar(32));
create table person_attributes (id int not null,
person_id int not null,
attribute varchar(32) not null,
value varchar(64) not null);
insert into person_attributes values (1, 1, 'age', '21');
insert into person_attributes values (2, 1, 'hair', 'brown');
insert into person_attributes values (3, 2, 'age', '32');
insert into person_attributes values (4, 2, 'music', 'jazz');
And this is my current select statement:
select * from person join person_attributes on
person.id = person_attributes.person_id
where attribute = 'hair';
Obviously Peter is not in the result set because we have no information about his hair. I would like to get him into the result set as well, but with null value.
The best would be if the result set was like
Person, Hair color
John, brown
Peter, null
I would like to avoid subqueries if possible, but if it is impossible to do with joins then they are welcome.
An outer join will do this:
select p.*, pa.value
from person p
left join person_attributes pa
on p.id = pa.person_id
and pa.attribute = 'hair';
Note that the condition for the "outer joined" table needs to go into the JOIN clause, not into the where clause. If the condition was in the where clause it would effectively turn the outer join into an inner join. This is because pa.attribute would be null due to the outer join, and the where would not match the null value thus eliminating all the rows that should actually stay in the result.
SQFiddle based on your example: http://sqlfiddle.com/#!12/d0342/1
I'm having a lot of troubles with the last query I need and I think it's a level out of my league so any help is appreciated.
The tables:
CREATE TABLE Recipe
(
nrecipe integer,
name varchar(255),
primary key (nrecipe)
);
CREATE TABLE Food
(
designation varchar(255) unique,
quantity integer,
primary key (designation)
);
CREATE TABLE Contains
(
nrecipe integer,
designation varchar(255),
quantity integer,
primary key (nrecipe, designation),
foreign key (nrecipe) references Recepie (nrecipe),
foreign key (designation) references Food (designation)
);
Quantity in Food table is the quantity stored in warehouse.
Quantity in Contains is the amount needed of a food element to use in recipe.
Quantity in Food table and Contains differ from each other.
The query:
I want to know the names of ALL recipes that are possible to be done with the food stored in warehouse.
It requires that the quantity of every element of food in warehouse is bigger than the quantity needed for the recipe.
EDIT: also, it shouldn't show a recipe's name if there is nothing referring to it on Contains table.
To make it easier to understand, I'll give some data:
INSERT INTO Recipe VALUES ('01', 'Steak with potatos and water');
INSERT INTO Recipe VALUES ('02', 'Rice and ice tea');
INSERT INTO Recipe VALUES ('03', 'Potatos and shrimp');
INSERT INTO Recipe VALUES ('04', 'Water');
INSERT INTO Recipe VALUES ('05', 'Steak with rice');
INSERT INTO Recipe VALUES ('06', 'Steak with spaguetti');
INSERT INTO Recipe VALUES ('07', 'Potatos with rice');
INSERT INTO Food VALUES ('Water', 5);
INSERT INTO Food VALUES ('Ice tea', 10);
INSERT INTO Food VALUES ('Steak', 30);
INSERT INTO Food VALUES ('Potatos', 20);
INSERT INTO Food VALUES ('Rice', 50);
INSERT INTO Food VALUES ('Shrimp', 5);
INSERT INTO Food VALUES ('Spaguetti', 5);
INSERT INTO Contains VALUES ('01', 'Steak', 1);
INSERT INTO Contains VALUES ('01', 'Potatos', 15);
INSERT INTO Contains VALUES ('01', 'Water', 10);
INSERT INTO Contains VALUES ('02', 'Rice', 5);
INSERT INTO Contains VALUES ('02', 'Ice tea', 8);
INSERT INTO Contains VALUES ('03', 'Potatos', 1);
INSERT INTO Contains VALUES ('03', 'Shrimp', 10);
INSERT INTO Contains VALUES ('04', 'Water', 20);
INSERT INTO Contains VALUES ('05', 'Steak', 1);
INSERT INTO Contains VALUES ('05', 'Rice', 20);
INSERT INTO Contains VALUES ('06', 'Steak', 1);
INSERT INTO Contains VALUES ('06', 'Spaguetti', 10);
The outcome expected from the query is:
Rice and ice tea
Steak with rice
Since it's the only two recipes with enough quantity in warehouse.
EDIT: potatoes with rice shouldn't appear as it is a recipe but isn't in contains list
Thanks for input and time. Any help is welcome :)
I'd use >= ALL operator :
SELECT name
FROM Recipe R
WHERE 0 >= ALL (SELECT C.quantity - F.quantity
FROM Food F
INNER JOIN Contains C
USING (designation)
WHERE C.nrecipe = R.nrecipe);
The correct spelling is recipe, and you used different names for some columns (recepie, nrecipe, nrecepie) so I changed it. Note that instead of using a varchar primary key, you should use a numeric one.
Edit:
SELECT name
FROM Recipe R
WHERE 0 >= ALL (SELECT C.quantity - F.quantity
FROM Food F
INNER JOIN Contains C
USING (designation)
WHERE C.nrecipe = R.nrecipe)
AND EXISTS(SELECT NULL
FROM Contains C
WHERE C.nrecipe = R.nrecipe);
This is in SQL Server because that is what I have:
select
r.name
from
Recepie r
where
not exists
(
select 1
from
[Contains] c
where
c.nrecipe = r.nrecepie and
not exists
(
select 1
from
Food f
where
f.designation = c.designation and
f.quantity >= c.quantity
)
)
Which in plain language is "Get me all recipes where there are no ingredients of insufficient quantity"