sql query select combined select from multiple table - sql

I really don't know what the title should be, but here the question
I have 2 table (actually more)
table a table b
id (pk)| country id(fk)| Branch
------ | ------ ------|--------
01 | Indonesia 01 | Jakarta
01 | Bali
if i do select * from a,b where a.id=b.id
the result will be
id | Country |Branch
01 | Indonesia|Jakarta
01 | Indonesia|Bali
I want the result to be like below
id | Country | Branch
01 | Indonesia | Jakarta,Bali
Is it possible?
I dont really trying to do research(i mean searching) as I don't know what keyword should I search

When using MySQL, GROUP_CONCAT is the function you're looking for.
Set up the tables like in the request above:
create table a (
`id` int(15) auto_increment primary key,
`country` varchar(200)
);
create table b (
`id` int(15) not null,
`branch` varchar(200),
foreign key(`id`) references a(`id`)
);
insert into a values (1, 'Indonesia');
insert into b values (1, 'Jakarta');
insert into b values (1, 'Bali');
Perform the query:
select a.id,
a.country,
group_concat(distinct b.branch) as 'branch'
from a
left join b on a.id=b.id;
Output:
| id | country | branch |
|----|-----------|--------------|
| 1 | Indonesia | Jakarta,Bali |

Related

SQL , Cross join alternative/faster solution

We have a simple table with two columns like
+-------+-------+
| fname | lname |
+-------+-------+
| foo | bar |
+-------+-------+
we also have another table which contains Months
+-------+
| month |
+-------+
| jan |
| feb |
| mar |
+-------+
The goal is to get a table like:
+-------+-------+-------+
| fname | lname | month |
+-------+-------+-------+
| foo | bar | jan |
| foo | bar | feb |
| foo | bar | mar |
+-------+-------+-------+
To get this table, I used a cross join, but the fetching time has increased exponentially when data are increased. This should be a simple duplication of data, and just the month column should be added at the end of each row, but it seems more complex behind the scenes. Can this query be run faster in any alternative way?
data
CREATE TABLE table1(fname varchar(100),lname varchar(100))
insert into table1
(fname,lname) values
('foo','bar');
CREATE TABLE table2(month varchar(100))
insert into table2
(month) values
('jan'),
('feb'),
('mar');
the alternative way is using Cross Apply but it is slower than Cross Join
SELECT fname,
lname,
month
FROM table2
CROSS apply (SELECT *
FROM table1
WHERE 1 = 1) A
if your first table has one row structure forget cross join and use value and alias
SELECT 'foo' fname,
'bar' lname,
month
FROM table2
or
declare #fname varchar(100)=(select fname from table1)
declare #lname varchar(100)=(select lname from table1)
select #fname fname,
#lname lname,
month
FROM table2
dbfiddle

Combining duplicate SQLite columns after joining parent with multiple children

I've got a SQLite database set up which looks like this:
I'm currently looking to join all of the child tables into the parent table. As you can see, all of the children are designed in the same way, so I was hoping that they would merge nicely together.
Unfortunately, joining the tables with a left join results in this:
With SQLite, is it possible to merge the columns so that the null values are ignored, and the remaining starting_item_ids and item_ids all display in the same column?
Any help would be greatly appreciated.
Edit: Here's a minimal reproducible example
CREATE TABLE `starting_item` (
`starting_item_id` integer PRIMARY KEY AUTOINCREMENT,
`quantity` integer
);
CREATE TABLE `starting_weapon` (
`starting_item_id` integer,
`item_id` integer,
FOREIGN KEY (`starting_item_id`) REFERENCES `starting_item` (`starting_item_id`)
);
CREATE TABLE `starting_armor` (
`starting_item_id` integer,
`item_id` integer,
FOREIGN KEY (`starting_item_id`) REFERENCES `starting_item` (`starting_item_id`)
);
CREATE TABLE `starting_gear` (
`starting_item_id` integer,
`item_id` integer,
FOREIGN KEY (`starting_item_id`) REFERENCES `starting_item` (`starting_item_id`)
);
CREATE TABLE `starting_tool` (
`starting_item_id` integer,
`item_id` integer,
FOREIGN KEY (`starting_item_id`) REFERENCES `starting_item` (`starting_item_id`)
);
INSERT INTO starting_item (quantity) VALUES (1);
INSERT INTO starting_item (quantity) VALUES (1);
INSERT INTO starting_item (quantity) VALUES (1);
INSERT INTO starting_item (quantity) VALUES (1);
INSERT INTO starting_weapon (starting_item_id, item_id) VALUES (1, 4);
INSERT INTO starting_armor (starting_item_id, item_id) VALUES (2, 7);
INSERT INTO starting_gear (starting_item_id, item_id) VALUES (3, 30);
INSERT INTO starting_tool (starting_item_id, item_id) VALUES (4, 20);
select * from starting_item
left join starting_weapon on starting_weapon.starting_item_id = starting_item.starting_item_id
left join starting_armor on starting_armor.starting_item_id = starting_item.starting_item_id
left join starting_gear on starting_gear.starting_item_id = starting_item.starting_item_id
left join starting_tool on starting_tool.starting_item_id = starting_item.starting_item_id
Current result:
+------------------+----------+------------------+---------+------------------+---------+------------------+---------+------------------+---------+
| starting_item_id | quantity | starting_item_id | item_id | starting_item_id | item_id | starting_item_id | item_id | starting_item_id | item_id |
+------------------+----------+------------------+---------+------------------+---------+------------------+---------+------------------+---------+
| 1 | 1 | 1 | 4 | | | | | | |
+------------------+----------+------------------+---------+------------------+---------+------------------+---------+------------------+---------+
| 2 | 1 | | | 2 | 7 | | | | |
+------------------+----------+------------------+---------+------------------+---------+------------------+---------+------------------+---------+
| 3 | 1 | | | | | 3 | 30 | | |
+------------------+----------+------------------+---------+------------------+---------+------------------+---------+------------------+---------+
| 4 | 1 | | | | | | | 4 | 20 |
+------------------+----------+------------------+---------+------------------+---------+------------------+---------+------------------+---------+
Intended Result:
+------------------+----------+------------------+---------+
| starting_item_id | quantity | starting_item_id | item_id |
+------------------+----------+------------------+---------+
| 1 | 1 | 1 | 4 |
+------------------+----------+------------------+---------+
| 2 | 1 | 2 | 7 |
+------------------+----------+------------------+---------+
| 3 | 1 | 3 | 30 |
+------------------+----------+------------------+---------+
| 4 | 1 | 4 | 20 |
+------------------+----------+------------------+---------+
You can have the stated desired output (minus frames, but that is just a config thing), with this query:
select * from starting_item a
join ( select * from starting_weapon
union select * from starting_armor
union select * from starting_gear
union select * from starting_tool) b
on a.starting_item_id=b.starting_item_id;
It uses a multi "union" of the identically structured subtables and joins it with the starting item table, using aliases "a" and "b".
The result is quite exactly the stated desired output:
starting_item_id quantity starting_item_id item_id
---------------- ---------- ---------------- ----------
1 1 1 4
2 1 2 7
3 1 3 30
4 1 4 20
However, in my opinion avoiding the redundant column (twice the ID) is desireable.
And I also feel somehow that a little trick to add an indicator (what kind of item we are seeing) is helpful. So I offer this for prettiness:
select * from starting_item
join ( select *, "weapon" kind from starting_weapon
union select *, "armor" kind from starting_armor
union select *, "gear" kind from starting_gear
union select *, "tool" kind from starting_tool)
using(starting_item_id);
It gets you, in case you like it:
starting_item_id quantity item_id kind
---------------- ---------- ---------- ----------
1 1 4 weapon
2 1 7 armor
3 1 30 gear
4 1 20 tool
The first change is to join with using() instead of on ..., which (in spite of using * for convenience) gets you only one ID column.
The second change is to add a column named "kind" with explicitly given content in each "unioned" part. This "unions" and "joins" up nicely and gets you a named indicator column. The advantage is that you can e.g. order by that indicator column for some tidyness.
Finally, please consider whether the unioned table used here is not actually something which you can use in your database design. I.e. use one table for all items, with an additional "kind" column.

Insert on a child table and update FK on parent

I have a parent table with the following structure and data:
---------------------------------------------
| Id | TranslationId | Name |
---------------------------------------------
| 1 | NULL | Image1.jpg |
| 2 | NULL | Image7.jpg |
| 3 | NULL | Picture_Test.png |
---------------------------------------------
And the empty child table which holds the translated images:
-------------------------------------------------------------------------
| Id | De | Fr | En |
-------------------------------------------------------------------------
| | | | |
-------------------------------------------------------------------------
Now I'm looking for a single query statement or at least few queries which I can run without any further programming. Doing this job with scripting or programming would be easy but I have often situations where I need this kind of insert / update. And developing each time a small console app is not feasible.
At the end the two tables should look like this:
---------------------------------------------
| Id | TranslationId | Name |
---------------------------------------------
| 1 | 28 | NULL |
| 2 | 29 | NULL |
| 3 | 30 | NULL |
---------------------------------------------
-------------------------------------------------------------------------
| Id | De | Fr | En |
-------------------------------------------------------------------------
| 28 | Image1.jpg | NULL | NULL |
| 29 | Image7.jpg | NULL | NULL |
| 30 | Picture_Test.png | NULL | NULL |
-------------------------------------------------------------------------
Thank you for any advice.
You could do it something like the below :
INSERT INTO Child
(
Id
,De
,Fr
,En
)
OUTPUT Inserted.Id INTO #Temp
SELECT Id
,De
,Fr
,En
FROM #Values --If you are using a table type to insert into the Child table as a set based approach
;WITH CTE
AS
(
SELECT ROW_NUMBER() OVER(ORDER BY Id) AS Rnk
,Id
FROM #Temp
)
,CTE1 AS
(
SELECT ROW_NUMBER() OVER(ORDER BY Id) AS Rnk
,*
FROM Parent
)
UPDATE cte1
SET TranslationId = cte.Id
FROM CTE1 cte1
JOIN CTE cte ON cte.Rnk = cte1.Rnk
Demo, assuming Name is unique in the first table
create table tab1 (
id int identity
,TranslationId int null
,Name nvarchar(max) null
);
insert tab1 (Name)
values
('Image1.jpg')
,('Image7.jpg')
,('Picture_Test.png')
,(null)
create table tab2 (
id int identity (100,1)
,De nvarchar(max) null
,Fr nvarchar(max) null
,En nvarchar(max) null
);
-- Update them
declare #map table(
name nvarchar(max)
,ref int
);
insert tab2 (de)
output inserted.De, inserted.id
into #map(Name, ref)
select Name
from tab1 src
where Name is not null and not exists (select 1 from tab2 t2 where t2.De = src.Name);
update t1 set TranslationId = ref, Name = null
from tab1 t1
join #map m on t1.Name = m.Name;
select * from tab1;
select * from tab2;
I figured out in the meantime how to do it. Applied on the database, the query looks like this:
DECLARE #Temp TABLE (ImageId INT, Id INT)
MERGE INTO Translation USING
(
SELECT Image.Name AS Name, Image.Id AS ImageId
FROM Candidate
INNER JOIN Candidacy ON Candidate.Id = Candidacy.CandidateId
INNER JOIN Election ON Candidacy.ElectionId = Election.Id
INNER JOIN SmartVoteCandidate ON Candidate.Id = SmartVoteCandidate.CandidateId
INNER JOIN Image ON SmartVoteCandidate.SpiderImageId = Image.Id
WHERE Election.Id = 1575) AS temp ON 1 = 0
WHEN NOT MATCHED THEN
INSERT (De)
VALUES (temp.Name)
OUTPUT temp.ImageId, INSERTED.Id
INTO #Temp (ImageId, Id);
UPDATE Image
SET Image.TranslationId = t.Id, Name = NULL
FROM #Temp t
WHERE Image.Id = t.ImageId
The solution is heavily inspired by
Is it possible to for SQL Output clause to return a column not being inserted?
Using a join in a merge statement

Insert values from one table to another having different primary key

I have 2 tables. Tab A and Tab B
Tab A
Id Name
2 John
3 Peter
4 Rachel
I need to insert records in table B to get following:
Tab B
PrId ID Resident Date.
1 2 Yes 7/1/2018
2 3 Yes 7/1/2018
3 4 Yes 7/1/2018
PrId is the primary key of table B, Id comes from Table A and rest of the values are hard coded.
Please suggest the script to do the same
Are you looking to simply do a straight-forward insert from one table into another? If so, here's an example you can run in SSMS:
-- create table variables for illustration purposes --
DECLARE #tableA TABLE ( [Id] INT, [Name] VARCHAR(10) );
DECLARE #tableB TABLE ( [PrId] INT IDENTITY (1, 1), [Id] INT, [Resident] VARCHAR(10), [Date] SMALLDATETIME );
-- insert sample data into #tableA --
INSERT INTO #tableA ( [Id], [Name] ) VALUES ( 2, 'John' ), ( 3, 'Peter' ), ( 4, 'Rachel' );
-- show rows in #tableA --
SELECT * FROM #tableA;
/*
+----+--------+
| Id | Name |
+----+--------+
| 2 | John |
| 3 | Peter |
| 4 | Rachel |
+----+--------+
*/
-- insert records from #tableA to #tableB --
INSERT INTO #tableB (
[Id], [Resident], [Date]
)
SELECT
[Id], 'Yes', '07/01/2018'
FROM #tableA;
-- show inserted rows in #tableB --
SELECT * FROM #tableB;
/*
+------+----+----------+---------------------+
| PrId | Id | Resident | Date |
+------+----+----------+---------------------+
| 1 | 2 | Yes | 2018-07-01 00:00:00 |
| 2 | 3 | Yes | 2018-07-01 00:00:00 |
| 3 | 4 | Yes | 2018-07-01 00:00:00 |
+------+----+----------+---------------------+
*/
If you have your tables set up with a Primary Key and Foreign Key then you can run the following select query to join the two tables into one.
select a.PrId, b.ID, a.Resident, a.Date
from Table a inner join
Table b on a.PrID = b.ID
look up inner joins here https://www.w3schools.com/sql/sql_join_inner.asp
and foreign key https://www.w3schools.com/sql/sql_foreignkey.asp
In the future please do some research before posting

How can we clone a set of one-to-many records?

There is a one-to-many relationship between two tables. Each table has its own identity primary key id. The problem is cloning some ( or for simplicity all ) of records in Table1 and their related records in Table2, then we will make a copy of all of records in Table1 and Table2 in the same Tables.
For example consider this example:
CREATE TABLE Categories
(
Id INT IDENTITY,
OtherData INT
)
CREATE TABLE Products
(
Id INT IDENTITY,
CategoryId INT CONSTRAINT FK_Category_Products
FOREIGN KEY REFERENCES dbo.Categories(Id),
ProductData INT
)
How can we make this copy. there is no restriction in how many commands is used, in order making this to be done.
Edit:
The main problem is saving one-two-many relationship between records while they are to be copied.
Example:
Categories: Products:
| Id | OtherData | | Id | CategoryId | ProductData |
|------|-------------| |------|-------------|---------------|
| 1 | 10 | | 11 | 1 | 20 |
| 2 | 10 | | 12 | 2 | 30 |
After copy we want this data:
Categories: Products:
| Id | OtherData | | Id | CategoryId | ProductData |
|------|-------------| |------|-------------|---------------|
| 1 | 10 | | 11 | 1 | 20 |
| 2 | 10 | | 12 | 2 | 30 |
| 3 | 10 | | 13 | 3 | 20 |
| 4 | 10 | | 14 | 4 | 30 |
Thanks for any help or suggestion.
As Ivan Starostin wrote in his comment, the trick is to use Merge to populate the parent categories, output the old id and new id into a map table, and use that map table to insert the products:
-- Declare the map table
DECLARE #Map as table
(
OldId int,
NewId int
)
-- Duplicate the records of the Categories table
MERGE INTO Categories
USING
(
SELECT Id, OtherData
FROM Categories
) As s ON 1 = 0 -- Always not matched
WHEN NOT MATCHED THEN
INSERT (OtherData)
VALUES (OtherData)
OUTPUT s.Id, Inserted.Id
INTO #Map (OldID, NewId); -- Note the output clause
-- Duplicate the records in the Products table (Note the inner join)
INSERT INTO Products (CategoryId, ProductData)
SELECT NewId, ProductData
FROM Products
INNER JOIN #Map m ON CategoryId = OldId