Receiving duplicated results from UNION in SQL - sql

I use SQL Server I use the following code:
CREATE TABLE table1
(
ID VARCHAR(10) NOT NULL PRIMARY KEY,
Name VARCHAR(3) NOT NULL,
Price INTEGER NOT NULL,
Date DATE
);
INSERT INTO table1 (ID, Name, Price, Date)
VALUES ('000212', 'Rod', 200, NULL);
CREATE TABLE table2
(
Descr VARCHAR(10) NOT NULL PRIMARY KEY,
Identity VARCHAR(10) NOT NULL,
amount INTEGER NOT NULL
);
INSERT INTO table2 (Descr, Identity, amount)
VALUES ('Silver rod', '000212', 3);
CREATE TABLE table3
(
Type VARCHAR(5) NOT NULL PRIMARY KEY,
Price INTEGER,
Condition INTEGER NOT NULL,
CatalogNum VARCHAR(10) NOT NULL
);
INSERT INTO table3 (Type, Price, Condition, CatalogNum)
VALUES ('Metal', NULL, 8, '000212');
INSERT INTO table3 (Type, Price, Condition, CatalogNum)
VALUES ('Wood', 300, 1, '000313');
WITH IdList AS
(
SELECT ID AS MasterId
FROM table1
UNION
SELECT Identity
FROM table2
UNION
SELECT CatalogNum
FROM table3
)
SELECT
i.MasterID,
t1.*,
t2.*,
t3.*
FROM
IdList as i
LEFT JOIN
table1 as t1 ON t1.ID = i.MasterID
LEFT JOIN
table2 as t2 ON t2.Identity = i.MasterID
LEFT JOIN
table3 as t3 ON t3.CatalogNum = i.MasterID;
SQL Fiddle demo
In order to combine several tables with the same product ID.
However for some reason I get multiple duplicated results. I.E. instead of getting one row with unique ID, I get 7 (I currently have 7 tables unlike the code above, but not necessarily - I also get 2, and 3 duplicated rows) with the same result.
Just to mention, this is a code which I found here and just edited and added 7 tables instead of only three that in the example above.

Related

SQL - Selecting a value from conditional joins without UNION

Setup
create table things ( `t1_id` int, `t2_id` int);
insert into things (`t1_id`, `t2_id`)
values ( NULL, 1), (NULL, 2), (1, NULL),(2,NULL);
create table type_1 (`id` int, `name` TEXT);
insert into type_1 (`id`, `name`)
values (1, 'name 1'), (2, 'name2');
create table type_2 (`id` int, `name` TEXT);
insert into type_2 (`id`, `name`)
values (1, 'name 3'), (2, 'name4');
Query
select coalesce (t1.name, t2.name) as name
from things
join type_1 as t1 on things.t1_id IS NOT NULL AND things.t1_id = t1.id
join type_2 as t2 on things.t2_id IS NOT NULL AND things.t2_id = t2.id
group by name
Fiddle: http://sqlfiddle.com/#!9/cfce11/7
I have what I've set out in the fiddle working with UNION, but in reality the rest of the query is expensive and the union doubled this - I'll probably need to do this for a second column too (name2 from type_3 and type_4 could be in this example, things would always have either t1_id or t2_id and either t3_id or t4_id - I'm assuming the same solution would work).
I'm looking for name to be selected from one table or another depending on whether the relevant column in 'things' is null.. I could use a 'type' column in things to differentiate if it would be better.
The fiddle should return all 4 names.
You are inner joining t1 and t2, but a thing cannot match t1 and t2 at the same time, so you get no results.
Join query
select distinct coalesce (t1.name, t2.name) as name
from things
left join type_1 as t1 on things.t1_id = t1.id
left join type_2 as t2 on things.t2_id = t2.id;
Union query
select name from type_1 where id in (select t1_id from things)
union
select name from type_2 where id in (select t2_id from things);
Both queries do the same thing. They give you all distinct names that are referenced in the things table.

oracle subquery stored into a variable

I have 2 tables table1 and table2.
create table table1
(
ID integer,
reg_number varchar(9),
primary_number varchar(9),
act varchar(1)
);
create table table2
(
SECONDARY_NUMBER varchar(9),
table1_id integer
);
I need to be able to grab all the rows from table1 that is associated with table2 so after an insert or update on column act from table1 to insert those rows into table3 table.
I have the query but I'm unsure how to store that query into a variable so I can call it into from a trigger.
The query
select * from table1 where id in (
with children as (
select id pid, primary_number pan from table1
where id = 20407 -- current id
and primary_number is not null -- child ids only
),
prime as (
select id pid from table1 p
inner join children c on c.pan = p.reg_number),
sibs as (
select secondary_number sec from table2 c
inner join prime on prime.pid = c.person_id ),
sibids as (
select id pid from table1 p
inner join sibs s on s.sec = p.reg_number)
select pid from children
union
select pid from prime
union
select pid from sibids
);
Thank you

select mutiple columns from 1 table insert into multiple rows of another table

how do I select multiple columns from table1 and insert into multiple rows of table2 if the values is not null
create table table2
(
label_id NUMBER(4),
level_name VARCHAR2(20)
);
create table table1
(
level_name VARCHAR2(20),
class_name1 VARCHAR2(20),
class_name2 VARCHAR2(20),
class_name3 VARCHARS2(20)
)
create table table2
(
level_id NUMBER(4),
class_name VARCHAR2(20)
)
data in table0
1, k1
2, k2
data in table1
k1, roomA5, roomA6, roomA7
k2, roomB1, roomB2
the result table2
1, roomA5
1, roomA6
1, roomA7
2, roomB1
2, roomB2
I probably need to add another column in table2 to make it right. perhaps table2 should be(level_id, room_id, class_name)
thank you so much for the any help
Try with:
insert into Table2 t2
(
Level_Id,
Class_Name
)select
t0.Level_Id,
t1.Class_Name1
from Table0 t0
inner join Table1 t1 on t1.level_name = t0.level_name
Do it with each class, just must replace Class_Name1 with Class_Name2.
Here is how to do it, easy if you union all 3 select statements for each classname column.
insert into table2
select a.level_id, b.classname1
from table0 a
join table1 b on a.level_name = b.level_name
where b.classname1 is not null
union all
select a.level_id, b.classname2
from table0 a
join table1 b on a.level_name = b.level_name
where b.classname2 is not null
union all
select a.level_id, b.classname3
from table0 a
join table1 b on a.level_name = b.level_name
where b.classname3 is not null
Have you looked at the unpivot command?
http://www.oracle.com/technetwork/articles/sql/11g-pivot-097235.html
Of course, this assumes you are using oracle 11g, which is an assumption at this point.
insert into table2
select *
from table1
unpivot
(
level_name
for class_name in ("class_name1","class_name2","class_name3")
)
order by "Puchase Frequency", state_code
I don't have a DB to test with, but this might help. It seems like a clean way to do it.

JOIN - Get one full table and the rest of another

Hi guys here is my Schema: http://sqlfiddle.com/#!4/82771
CREATE TABLE t1
(
Age INT,
Name VARCHAR(20)
);
CREATE TABLE t2
(
Age INT,
Name VARCHAR(20)
);
INSERT INTO t1(Age, Name) VALUES(31, NULL);
INSERT INTO t1(Age, Name) VALUES(32, NULL);
INSERT INTO t1(Age, Name) VALUES(33, NULL);
INSERT INTO t1(Age, Name) VALUES(34, NULL);
INSERT INTO t2(Age, Name) VALUES(31, 'Panos');
I need a Join query that will give me this Result:
Age Name
31 'Panos'
32 Null
33 Null
34 Null
I've tried LEFT JOIN and RIGHT JOIN on Age but I can't get what I need. It should be pretty simple but its just not coming to me...
maybe you have missed something when you are doing LEFT JOIN. Use also coalesce to return the first non-null value.
SELECT t1.Age, COALESCE(t2.name, t1.Name) Name
FROM t1
LEFT JOIN t2
ON t1.Age = t2.Age
SQLFiddle Demo
One way is to use union all and then check for non-existence in the second table:
select *
from t1
union all
select *
from t2
where Not exists (select 1 from t1 where t1.age = t2.age)

Return values from different tables based on a priority

Assuming I have three tables :
TableA (key, value)
TableB (key, value)
TableC (key, value)
and I want to return a value for all keys. If the key exists in TableC return that value else if the key exists in B return that value else return the value from table A
The best I have come up with so far is
SELECT key,Value
FROM TableA
WHERE key NOT IN (SELECT key FROM TableB)
AND key NOT IN (SELECT key FROM TableC)
UNION
SELECT key,Value
FROM TableB
WHERE key NOT IN (SELECT key FROM TableC)
UNION
SELECT key,Value
FROM TableC
But this seems pretty brute force. Anyone know a better way?
Edit: Here is a more concrete example. Consider TableA as a standard work schedule where the key is a date and the value is the assigned shift. Table B is a statutory holiday calendar that overrides the standard work week. Table C is an exception schedule that is used to override the other two schedules when someone is asked to come in and work either an extra shift or a different shift.
OK, using your concrete example as a basis, I came up with a solution different from the others posted (although I think I like your solution better). This was tested on MS SQL Server 2005 - changes may be needed for your SQL dialect.
First, some DDL to set the stage:
CREATE TABLE [dbo].[StandardSchedule](
[scheduledate] [datetime] NOT NULL,
[shift] [varchar](25) NOT NULL,
CONSTRAINT [PK_StandardSchedule] PRIMARY KEY CLUSTERED
( [scheduledate] ASC ));
CREATE TABLE [dbo].[HolidaySchedule](
[holidaydate] [datetime] NOT NULL,
[shift] [varchar](25) NOT NULL,
CONSTRAINT [PK_HolidaySchedule] PRIMARY KEY CLUSTERED
( [holidaydate] ASC ));
CREATE TABLE [dbo].[ExceptionSchedule](
[exceptiondate] [datetime] NOT NULL,
[shift] [varchar](25) NOT NULL,
CONSTRAINT [PK_ExceptionDate] PRIMARY KEY CLUSTERED
( [exceptiondate] ASC ));
INSERT INTO ExceptionSchedule VALUES ('2008.01.06', 'ExceptionShift1');
INSERT INTO ExceptionSchedule VALUES ('2008.01.08', 'ExceptionShift2');
INSERT INTO ExceptionSchedule VALUES ('2008.01.10', 'ExceptionShift3');
INSERT INTO HolidaySchedule VALUES ('2008.01.01', 'HolidayShift1');
INSERT INTO HolidaySchedule VALUES ('2008.01.06', 'HolidayShift2');
INSERT INTO HolidaySchedule VALUES ('2008.01.09', 'HolidayShift3');
INSERT INTO StandardSchedule VALUES ('2008.01.01', 'RegularShift1');
INSERT INTO StandardSchedule VALUES ('2008.01.02', 'RegularShift2');
INSERT INTO StandardSchedule VALUES ('2008.01.03', 'RegularShift3');
INSERT INTO StandardSchedule VALUES ('2008.01.04', 'RegularShift4');
INSERT INTO StandardSchedule VALUES ('2008.01.05', 'RegularShift5');
INSERT INTO StandardSchedule VALUES ('2008.01.07', 'RegularShift6');
INSERT INTO StandardSchedule VALUES ('2008.01.09', 'RegularShift7');
INSERT INTO StandardSchedule VALUES ('2008.01.10', 'RegularShift8');
Using these tables/rows as a basis, this SELECT statement retrieves the desired data:
SELECT DISTINCT
COALESCE(e2.exceptiondate, e.exceptiondate, holidaydate, scheduledate) AS ShiftDate,
COALESCE(e2.shift, e.shift, h.shift, s.shift) AS Shift
FROM standardschedule s
FULL OUTER JOIN holidayschedule h ON s.scheduledate = h.holidaydate
FULL OUTER JOIN exceptionschedule e ON h.holidaydate = e.exceptiondate
FULL OUTER JOIN exceptionschedule e2 ON s.scheduledate = e2.exceptiondate
ORDER BY shiftdate
Here is an alternate SQL statement:-
SELECT
ALL_KEYS.KEY,
NVL( TABLEC.VALUE, NVL( TABLEB.VALUE, TABLEA.VALUE)) AS VALUE
FROM
(SELECT KEY AS KEY FROM TABLEA
UNION
SELECT KEY FROM TABLEB
UNION
SELECT KEY FROM TABLEC) ALL_KEYS,
TABLEA,
TABLEB,
TABLEC
WHERE
ALL_KEYS.KEY = TABLEA.KEY(+) AND
ALL_KEYS.KEY = TABLEB.KEY(+) AND
ALL_KEYS.KEY = TABLEC.KEY(+);
NB. The NVL() is an Oracle function. If the first parameter is NULL, the second parameter is returned otherwise the first parameter is returned. You didn't say which database you were using but no doubt there are equivalents in everything.
If you have a number of tables that you want data from, then you are going to have to select from them, there is no other way around it.
From your SQL, it seems that you could get restuls from tableC that contains keys in tableA and tableB, as you are UNION-ing the restuls of a simple select on tableC (of which there is no where clause). Where you after an exclusive set of keys that do NOT exist in any of the other tables? If so, then you will need to do what you did for the where clause for tableA in the selects for tableB and tableC.
I hope that makes sense...
Here's how I would do it in SQL Server. This solution should generate less logical IO than the original. If the tables were sufficiently huge, I would swap over to #temp tables to enable parallelism.
DECLARE #MyTable TABLE
(
Key int PRIMARY KEY,
Value int
)
--Grab from TableC
INSERT INTO #MyTable(Key, Value)
SELECT Key, Value
FROM TableC
--Grab from TableB
INSERT INTO #MyTable(Key, Value)
SELECT Key, Value
FROM TableB
WHERE Key not in (SELECT Key FROM #MyTable)
--Grab from TableA
INSERT INTO #MyTable(Key, Value)
SELECT Key, Value
FROM TableA
WHERE Key not in (SELECT Key FROM #MyTable)
--Pop the result
SELECT Key, Value
FROM #MyTable
This technique mirrors how I would handle 3 lists in C#... by creating a dictionary.
Your query looks fine.
Alternatively, you can use the query below and filter on the client side. It will be less stressful for the database server.
SELECT key, value, 2 AS priority
FROM TableA
UNION
SELECT key, value, 1 AS priority
FROM TableB
UNION
SELECT key, value, 0 AS priority
FROM TableC
ORDER BY key, priority
SELECT isnull( c.key, isnull( b.key, a.key) ) ,
isnull( c.value, isnull( b.value, a.value ) )
FROM TableA a
LEFT JOIN TableB b
ON a.key = b.key
LEFT JOIN TableC c
ON b.key = c.key
Create a master table of all keys, then left join this master table to the three tables and investigate the COALESCE command.