How to query a table with 2 foreign keys? - sql

I have three tables in my android app.
Table Animal Table Group TableGroup_Animal
idAnimal idGroup idAnimal
AnimalName groupName idGroup
I want to know how to do query in order to get all the animals inside a group. The query I made is this
select
Groups.groupName
from
Groups,
Animal,
tableGrupo_Animal
where
Animal.idanimal = tableGroup_Animal.fkanimal
and
Groups.idgrupo = tableGrupo_Animal.fkgrupo
group by
group.groupName
And also this(That only shows the first row)
select
*
from
Animal
INNER JOIN " + tableGroup + " ON Animal.idanimal = Group.idGroup
where
Group.groupName = ' " + groupName +
As I said I want to get all the animals inside a group, how can I do that? Thanks

I recreated your database in sqlite and tested this out. This SQL works fine. I'd suggest that you rename your table "Group" as it's a reserved word in SQL and you'll have to back tick it every time as I do in this sql.
select a.AnimalName, g.groupName
from Animal a
JOIN TableGroup_Animal tga ON a.idAnimal = tga.idAnimal
JOIN `Group` g on g.idGroup= tga.idGroup;
Here's the schema I created and data to help anyone trying to prototype this.
CREATE TABLE `Animal` (
`idAnimal` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
`animalName` varchar(128)
);
CREATE TABLE `Group` (
`idGroup` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
`groupName` varchar(128)
);
CREATE TABLE `TableGroup_Animal` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
`idAnimal` integer,
`idGroup` integer
);
--Seeding animal
insert into `Animal` (animalName) values ('cat');
insert into `Animal` (animalName) values ('Rat');
insert into `Animal` (animalName) values ('Zebra');
insert into `Animal` (animalName) values ('Platypus');
--seeding group
insert into `Group` (groupName) values ('small');
insert into `Group` (groupName) values ('medium');
insert into `Group` (groupName) values ('large');
---seeding group animal pivot table
insert into TableGroup_Animal (idAnimal, idGroup) values (3,2);
insert into TableGroup_Animal (idAnimal, idGroup) values (3,3);
insert into TableGroup_Animal (idAnimal, idGroup) values (1,2);
insert into TableGroup_Animal (idAnimal, idGroup) values (4,2);
insert into TableGroup_Animal (idAnimal, idGroup) values (2,1);
);
insert into TableGroup_Animal (idAnimal, idGroup) values (2,1);

Do this query:
select * from Animal INNER JOIN tableGrupo_Animal ON Animal.idanimal = tableGrupo_Animal.fkanimal INNER JOIN Grupos ON Grupos.idgrupo = tableGrupo_Animal.fkgrupo where Grupos.nomegrupo='wwrt'

Related

Update multiple tables in trigger where one of the tables is used for trigger activation

Let's say I have two tables called widgetCustomer and widgetSale. On an insert in widgetSale I want to add a timestamp to the widgetSale row and add the sale id as last_order_id to the widgetCustomer table.
I understand using AFTER INSERT ON will result in an error on trying to update the NEW row, hence we need to use BEFORE INSERT ON clause. Which brings forward a new issue that AUTO_INCREMENT has not yet generated a id for sale hence last_order_id would all be zero. There is a method to do this at MySQL/MariaDB TRIGGER but it seems to fail on my system (i.e., the last order ids are still zero).
As a work around I'm using two different triggers one before insert and one after insert. Although it does work I'm keen to learn if there is a possible flaws with the method above and is there a better way of doing this (both in terms of performance and data integrity).
My code is given below:
DROP TABLE IF EXISTS widgetSale;
DROP TABLE IF EXISTS widgetCustomer;
DROP TABLE IF EXISTS widgetLog;
CREATE TABLE widgetCustomer ( id integer primary key AUTO_INCREMENT, name TEXT, last_order_id INT, stamp TEXT );
CREATE TABLE widgetSale ( id integer primary key AUTO_INCREMENT, item_id INT, customer_id INTEGER, quan INT, price INT, stamp TEXT );
CREATE TABLE widgetLog ( id integer primary key AUTO_INCREMENT, stamp TEXT, event TEXT, username TEXT, tablename TEXT, table_id INT);
INSERT INTO widgetCustomer (name) VALUES ('Bob');
INSERT INTO widgetCustomer (name) VALUES ('Sally');
INSERT INTO widgetCustomer (name) VALUES ('Fred');
SELECT * FROM widgetCustomer;
CREATE TRIGGER stampSale BEFORE INSERT ON widgetSale
FOR EACH ROW BEGIN
SET NEW.stamp = CURRENT_TIMESTAMP();
END
CREATE TRIGGER stampOnRest AFTER INSERT ON widgetSale
FOR EACH ROW BEGIN
UPDATE widgetCustomer SET last_order_id = NEW.id, stamp = CURRENT_TIMESTAMP()
WHERE widgetCustomer.id = NEW.customer_id;
INSERT INTO widgetLog (stamp, event, username, tablename, table_id)
VALUES (CURRENT_TIMESTAMP(), 'INSERT', 'TRIGGER', 'widgetSale', NEW.id);
END
INSERT INTO widgetSale (item_id, customer_id, quan, price) VALUES (1, 3, 5, 1995);
INSERT INTO widgetSale (item_id, customer_id, quan, price) VALUES (2, 2, 3, 1495);
INSERT INTO widgetSale (item_id, customer_id, quan, price) VALUES (3, 1, 1, 2995);
SELECT * FROM widgetSale;
SELECT * FROM widgetCustomer;
SELECT * FROM widgetLog;
I'm using mariadb 10.6.* on Archlinux.

Finding trouble in generating the list of all Students who belongs to the major named as “CS” but not to major named as “EE”

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.

postgresql - use just created identity value to return newly inserted row

Using SQL Server I can write the following statement...
create table Person(
id int identity(1,1),
name varchar(50)
)
insert into Person(name) values ('John')
select * from Person where id = scope_identity()
In Postgres I can do this:
CREATE TABLE public.Person
(
id serial primary key,
name character varying(10) NOT NULL
)
INSERT INTO Person(name) VALUES ('Smith', 'John') RETURNING id;
How would I write an equivalent statement like I did in the SQL example where don't return the id, but the entire row that was just inserted?
As #cur4so stated, or alternatively
INSERT INTO Person(name) VALUES ('Smith', 'John') RETURNING *;
INSERT INTO Person (name) VALUES ('Smith John');
select * from Person where id = currval('person_id_seq');

How to use merge statement to split one staging tables into two for loading from Staging to RealtionalDB?

I have following tables. I want to insert values into companyGroup and Comapany from test1 table. what would be better way CTE or Using Merge directly and how can i do that using tsql. Test1 is on database A and company and companygroup are on database B.
create table test1
(
companyID int identity
,CompanyName Varchar(50)
,[Group] Varchar(5)
)
INSERT INTO (CompanyName, [Group]) values ('Unknown', '0')
INSERT INTO (CompanyName, [Group]) values ('APPLE', 'IOS')
INSERT INTO (CompanyName, [Group]) values ('Google', 'Android')
INSERT INTO (CompanyName, [Group]) values ('Samsung', 'Android')
INSERT INTO (CompanyName, [Group]) values ('Lg', 'IOS')
create table CompanyGroup
(
Groupkey int identity (0,1) primary key
,GroupName varchar(5)
) ;
INSERT INTO (GroupName) VALUES ('Unknown')
create table Company
(
compnayKey int identity (0,1) primary key
,CompanyName Varchar(50)
,companyGroupKey int References CompanyGroup(GroupKey)
)
INSERT INTO (CompanyName,companyGroupKey) VALUES ('Unknown',0)
when I insert the values into company how can i convert group to int ? Any ideas? What would be Best TSQL for this load.
Try using this:
INSERT INTO CompanyGroup(GroupName)
SELECT [Group]
FROM test1
WHERE NOT EXISTS(SELECT 1
FROM CompanyGroup
WHERE GroupName = [Group]);
MERGE Company AS target
USING (SELECT t.CompanyName, g.Groupkey
FROM test1 AS t
LEFT JOIN CompanyGroup AS g ON t.[Group] = g.GroupName
) AS source
ON (target.CompanyName = source.CompanyName
AND target.companyGroupKey = source.Groupkey)
WHEN NOT MATCHED THEN
INSERT (CompanyName, companyGroupKey)
VALUES (source.CompanyName, source.Groupkey);

Duplicating records efficiently in tsql

I've a scenario where I have a parent table which has '1 to many' relationships with two or three tables. These child tables again have '1 to many' relationships with more tables and so on. This goes up to 5 to 6 levels of hierarchy.
Now, based on single primary key value of the parent table, I want to duplicate all information related to it in database. I wrote a stored procedure which uses cursors and inserts child rows one by one and sets new foreign key values with each insert. But it is consuming some time because number of records in child tables is high.
Is there any other efficient way to do this?
In SQL Server 2008:
CREATE TABLE t_parent (id INT NOT NULL PRIMARY KEY IDENTITY, value VARCHAR(100))
CREATE TABLE t_child (id INT NOT NULL PRIMARY KEY IDENTITY, parent INT NOT NULL, value VARCHAR(100))
CREATE TABLE t_grandchild (id INT NOT NULL PRIMARY KEY IDENTITY, child INT NOT NULL, value VARCHAR(100))
INSERT
INTO t_parent (value)
VALUES ('Parent 1')
INSERT
INTO t_parent (value)
VALUES ('Parent 2')
INSERT
INTO t_child (parent, value)
VALUES (1, 'Child 2')
INSERT
INTO t_child (parent, value)
VALUES (2, 'Child 2')
INSERT
INTO t_grandchild (child, value)
VALUES (1, 'Grandchild 1')
INSERT
INTO t_grandchild (child, value)
VALUES (1, 'Grandchild 2')
INSERT
INTO t_grandchild (child, value)
VALUES (2, 'Grandchild 3')
DECLARE #tt TABLE (oid INT, nid INT)
MERGE
INTO t_parent
USING (
SELECT id, value
FROM t_parent
) p
ON 1 = 0
WHEN NOT MATCHED THEN
INSERT (value)
VALUES (value)
OUTPUT p.id, INSERTED.id
INTO #tt;
MERGE
INTO t_child
USING (
SELECT c.id, p.nid, c.value
FROM #tt p
JOIN t_child c
ON c.parent = p.oid
) c
ON 1 = 0
WHEN NOT MATCHED THEN
INSERT (parent, value)
VALUES (nid, value)
OUTPUT c.id, INSERTED.id
INTO #tt;
INSERT
INTO t_grandchild (child, value)
SELECT c.nid, gc.value
FROM #tt c
JOIN t_grandchild gc
ON gc.child = c.oid
In earlier versions of SQL Server, you will have to do a SELECT followed by an INSERT to find out the new values of the PRIMARY KEY.
You'll have to insert one table at a time, but you can do it by inserting sets instead of rows if you allow the FK values in the new parent's child tables to be the same as the FK values of the original parent.
Say you have a view of your parent table and in your sp you limit it to the row to copy from (pk=1, say).
Then insert that row into the parent table substituting PK=2 for the PK val.
Now use a second view of one of the child tables. In your sp, limit the set of rows to those with PK=1. Again, insert all those rows into that same child table substituting PK=2 for the PK field val.