View over multiple tables containing same columns - sql

I have four tables containing exactly the same columns, and want to create a view over all four so I can query them together.
Is this possible?
(for tedious reasons I cannot/am not permitted to combine them, which would make this irrelevant!)

Assuming that in addition to having the same column names, columns of the same contain the same data, you want to create a view that is the union of all those tables.
Something like the following should work, but my SQL is rusty:
(CREATE VIEW view_name AS
(SELECT * FROM table1
UNION
SELECT * FROM table2
UNION
SELECT * FROM table3));

It may be worth noting that you might need to use "union all" to preserve unique rows which may exist in more than one of the tables. A standard union will remove duplicates.

It is difficult to tell from your query whether you expect the data to be returned based on a UNION, or as a view containing the columns discretely. This obviously has an effect.
Consider the following sample:
TableA
ID Name RelatedID
1 John 2
2 Paul 1
TableB
ID Name RelatedID
1 Ringo 1
2 George 1
TableC
ID Name RelatedID
1 Bob 1
TableD
ID Name RelatedID
1 Kate NULL
Now, run the following query against this:
SELECT ID, Name FROM TableA
UNION ALL
SELECT ID, Name FROM TableB
UNION ALL
SELECT ID, Name FROM TableC
UNION ALL
SELECT ID, Name FROM TableD
This results in the following output:
1 John
2 Paul
1 Ringo
2 George
1 Bob
1 Kate
Is this what you are after? If so, you use a UNION query.
Now, if the effect you are after is to have a discrete view of related data, you may need to do something like this:
SELECT A.ID MasterID, A.Name MasterName,
B.ID BandID, B.Name BandName,
C.ID BlackadderID, C.Name BlackadderName
D.ID BlackadderRealID, D.Name BlackadderRealName
FROM
TableA A
INNER JOIN
TableB B
ON
A.RelatedID = B.ID
INNER JOIN
TableC C
ON
B.RelatedID = C.ID
INNER JOIN
TableD D
ON
C.RelatedID = D.ID
This will result in the following view of the data:
MasterID MasterName BandID BandName BlackAdderID BlackAdderName BlackadderRealID BlackadderRealName
1 John 2 George 1 Bob 1 Kate
2 Paul 1 Ringo 1 Bob 1 Kate

Use union.
Here is explanation

Use the union statement
select * from table1
union
select * from table2
union
select * from table3

You can if you union them (I would suggest including some indicator as to which table each record came from):
select table1.column1, 1 as TableNumber
from table1
union
select table2.column1, 2 as TableNumber
from table2
.. etc ..

Rather than UNION, use UNION ALL, unless you specifically want duplicate rows to be excluded. UNION on its own takes longer to execute (because of the sort it does to find dupes), and removes duplicate rows.

Related

merging two tables with a query

I'm newbie to sql.
There are two different tables with same columns and assume that Name unique.
TABLE_A
Name | AGE
-----------
Toby | 2
Milo | 1
Achmed| 3
TABLE_B
Name | AGE
-----------
Milo | 2
TABLE_B is my superior table, If TABLE_B name value contains in TABLE_A, than TABLE_B's value should be selected. RESULT is shown below.
RESULT is not a table, the result of query.
RESULT
Name | AGE
-----------
Toby | 2
Milo | 2
Achmed| 3
I have already solve this problem on the programming side, but I'm curries about the sql query to get this result.
TSQL or PLSQL doesnt matter.
You can use FULL JOIN to get all rows from both tables and COALESCE to give precedence to Table_B if Name exists in both tables.
SELECT
COALESCE (b.Name, a.Name) as Name
,COALESCE (b.Age, a.Age) as Age
FROM Table_A a
FULL JOIN Table_B b ON a.Name = b.Name
SQLFiddle DEMO
You can "fuse" both results using a union like this
SELECT Name, AGE FROM TABLE_A
UNION
SELECT Name, AGE FROM TABLE_B
ORDER BY Name;
The SQL statement selects all the different Names and Ages from the "TABLE_A" and the "TABLE_B" tables.
You could also eliminate any duplicates while using union, I think this would be faster than a full join:
SELECT Name, Age FROM Table_B
UNION
SELECT Name, Age FROM Table_A WHERE TABLE_A.NAME NOT IN (SELECT Name FROM Table_B)
ORDER BY Name;

SQL: Sort a table by the first relation to a second table

I have a Many-to-Many relationship between two tables. I'd like to sort the first table by the first relationship with the second table and only return a single result from that table. This is on SQL Server. I'd like something like this:
SELECT a.retrieve_me
FROM table_A AS a
JOIN table_B AS b ON a.foo = b.foo
JOIN table_C AS c ON b.bar = c.bar
ORDER BY c.sort_me
Unfortunately it returns MN(k) results, where M is the count of "table_A" and N(k) is the number of relations of a single row k with "table_C." To have it return just the results I wanted without post filtering I tried using DISTINCT on the SELECT clause and using TOP(SELECT COUNT(*) FROM table_A) but neither are valid syntax.
Any ideas? Hoping I can make this as performant as possible.
EDIT:
For clarity
table A
------------
"joe" 1
"betty" 2
"george" 3
table B
------------
1 2
1 3
2 3
2 4
3 1
table C
------------
1 "ashton"
2 "harding"
3 "spring"
4 "merry lane"
I'd like the results returned in the order of "george", "joe", and "betty" which is in the order (george -> ashton, joe -> harding, betty -> merry lane.)
If I understood correctly what you need, cause I think is very hard to follow you .. this should do it:
SELECT a.nm
FROM tablea a
cross apply (select top 1 *
from tableb b
join tablec c on b.id2 = c.id
where a.id = b.id1
order by c.nm) bc
order by bc.nm
http://sqlfiddle.com/#!3/661c0/5/0

How to get same results without using distinct in query

I have a table with data like so:
[ID, Name]
1, Bob
1, Joe
1, Joe
1, Bob
I want to retrieve a list of records showing the relationship between the records with the same ID.
For instance, I want the following result set from my query:
Bob, Joe
Joe, Bob
Bob, Bob
Joe, Joe
This shows me the "from" and "to" for every item in the table.
I can get this result by using the following query:
SELECT DISTINCT [NAME]
FROM TABLE A
INNER JOIN TABLE B ON A.ID = B.ID
Is there anyway for me to achieve the same result set without the use of the "distinct" in the select statement? If I don't include the distinct, I get back 16 records, not 4.
The reason you get duplicate rows without DISTINCT is because every row of ID = x will be joined with every other row with ID = x. Since the original table has (1, "Bob") twice, both of those will be joined to every row in the other table with ID = 1.
Removing duplicates before doing a join will do two things: decrease the time to run the query, and prevent duplicate rows from showing up in the result.
Something like (using MySQL version of SQL):
SELECT L.NAME, R.NAME
FROM (SELECT DISTINCT ID, NAME FROM A) AS L
INNER JOIN (SELECT DISTINCT ID, NAME FROM B) AS R
ON L.ID = R.ID
Edit: is B an alias for table A?
In SQL and MY SQL
SELECT COLUMN_NAME FROM TABLE_NAME group by COLUMN_NAME
Have you tried using a group by clause?
select name
from table a
inner join table b
on a.id=b.id
group by name
That should get you the same thing as your distinct query above. As for the result set that you want, a simple self join should do it:
select name1,name2
from(
select id,name as name1
from table
group by 1,2
)a
join(
select id,name as name2
from table
group by 1,2
)b
using(id)
Eliminating duplicate values with union without using distinct
Declare #TableWithDuplicateValue Table(Name Varchar(255))
Insert Into #TableWithDuplicateValue Values('Cat'),('Dog'),('Cat'),('Dog'),('Lion')
Select Name From #TableWithDuplicateValue
union
select null where 1=0
Go
Output
---------
Cat
Dog
Lion
For more alternate kindly visit my blog
http://www.w3hattrick.com/2016/05/getting-distinct-rows-or-value-using.html

SQL Getting Data with extra row

I have two tables with columns of my interests as Table1.Column1 and Table2.Column2
Table1 is Kind of a Group Table and Table2 is items table. The join query of these two tables gets the data in the followinf format
Column1 Column2
A 1
A 2
B 1
B 2
B 3
What I want is to get data in the following format:
Column1 Column2
A 0
A 1
A 2
B 0
B 1
B 2
B 3
i.e. getting extra 0 for each group at the start each time. The 0 does not exits in the database.
Does anyone know how to achive this in SQL?
Many Thanks,
This is one way to do it.
SELECT DISTINCT Column1, [Column2] = 0
FROM (
YourOriginalQuery
) q
UNION ALL
YourOriginalQuery
Most likely, there are better solutions by incorporating this requirement into your original query. If you post your query, we can come up with better alternatives.
Or something like:
select C.CategoryId, drv.CategoryGroupId from Category as C
cross join (
select 0 as CategoryGroupId
UNION
select CG.CategoryGroupId from CategoryGroup as CG
)drv order by CategoryId, CategoryGroupId

FULL OUTER JOIN with SQLite

SQLite only has INNER and LEFT JOIN.
Is there a way to do a FULL OUTER JOIN with SQLite?
Yes, see the example on Wikipedia.
SELECT employee.*, department.*
FROM employee
LEFT JOIN department
ON employee.DepartmentID = department.DepartmentID
UNION ALL
SELECT employee.*, department.*
FROM department
LEFT JOIN employee
ON employee.DepartmentID = department.DepartmentID
WHERE employee.DepartmentID IS NULL
FULL OUTER JOIN is natively supported starting from SQLite 3.39.0:
2.1. Determination of input data (FROM clause processing)
A "FULL JOIN" or "FULL OUTER JOIN" is a combination of a "LEFT JOIN" and a "RIGHT JOIN". Extra rows of output are added for each row in left dataset that matches no rows in the right, and for each row in the right dataset that matches no rows in the left. Unmatched columns are filled in with NULL.
Demo:
CREATE TABLE t1 AS
SELECT 1 AS id, 'A' AS col UNION
SELECT 2 AS id, 'B' AS col;
CREATE TABLE t2 AS
SELECT 1 AS id, 999 AS val UNION
SELECT 3 AS id, 100 AS val;
Query:
SELECT *
FROM t1
FULL JOIN t2
ON t1.id = t2.id;
db<>fiddle demo
Following Jonathan Leffler's comment in Mark Byers' answer, here's an alternative answer which uses UNION instead of UNION ALL:
SELECT * FROM table_name_1 LEFT OUTER JOIN table_name_2 ON id_1 = id_2
UNION
SELECT * FROM table_name_2 LEFT OUTER JOIN table_name_1 ON id_1 = id_2
Edit: The original source for the SQLite example above and from where further SQLite examples could be found was http://sqlite.awardspace.info/syntax/sqlitepg06.htm but it seems as though that site is now returning a 404 Not Found error.
For people, searching for an answer to emulate a Distinct Full Outer Join:
Due to the fact, that SQLite does neither support a Full Outer Join, nor a Right Join, i had to emulate a distinct full outer join / an inverted inner join (however you might call it).
The following Venn diagram shows the expected output:
To receive this expected output, i combined two Left Join clauses (the example refers to two identical built tables with partially differing data. I wanted to output only the data which does either appear in table A OR in table B).
SELECT A.flightNumber, A.offblockTime, A.airspaceCount, A.departure, A.arrival FROM D2flights A
LEFT JOIN D1flights B
ON A.flightNumber = B.flightNumber
WHERE B.flightNumber IS NULL
UNION
SELECT A.flightNumber, A.offblockTime, A.airspaceCount, A.departure, A.arrival FROM D1flights A
LEFT JOIN D2flights B
ON A.flightNumber = B.flightNumber
WHERE B.flightNumber IS NULL
The SQLite statement above returns the expected result in one query. It appears, that the UNION clause does also order the output via the flightNumber column.
The code has been tested with SQLite version 3.32.2
I will belatedly pitch in my 2 cents. Consider the 2 simple tables people1 and people2 below:
id name age
0 1 teo 59
1 2 niko 57
2 3 maria 54
id name weight
0 1 teo 186
1 2 maria 125
2 3 evi 108
First, we create a temporaty view, v_all, where we join with UNION the two opposite LEFT JOINS as below:
CREATE TEMP VIEW v_all AS
SELECT p1.name AS name1, p1.age,
p2.name AS name2, p2.weight
FROM people1 p1
LEFT JOIN people2 AS p2
USING (name)
UNION
SELECT p1.name AS name1, p1.age,
p2.name AS name2, p2.weight
FROM people2 AS p2
LEFT JOIN people1 AS p1
USING (name);
However, we end up with 2 name columns,name1 and name2, which may have a null value or equal values. What we want is to combine name1 and name2 in a single column name. We can do that with a CASE query as below:
SELECT age,weight,
CASE
WHEN name1 IS NULL
THEN name2
WHEN name2 IS NULL
THEN name1
WHEN name1=name2
THEN name1
END name
FROM v_all
And we finally end up with:
name weight age
0 evi 108 None
1 maria 125 54
2 niko None 57
3 teo 186 59
Of course you could combine the two in a single query, without having to create a temp view. I avoided doing so, in order to highlight the insufficiency of just 2 left joins and a union, which is what i have seen so far recommended.