SQL flat table query - sql

I have imported some data from an excel table in to an SQL table and I now need to write a view over the data to combine it with some other fields.
My problem is that the table is in the following form with these columns;
Name Project_One_ID Project_Two_ID Project_Three_ID
Rather than the form I could use, which would be a link table with columns like this;
Name ProjectID
Is it possible to convert this type of table? Or use it as it is? I could do it in code but im struggling in SQL. I have two other tables that need to link on to either side of this link table to create my overall view.
Thanks for any pointers,

You could do it as a UNION and then join to other tables:
SELECT * FROM
(
SELECT Name, Project_One_ID ProjectID
FROM Projects
UNION ALL
SELECT Name, Project_Two_ID ProjectID
FROM Projects
UNION ALL
SELECT Name, Project_Three_ID ProjectID
FROM Projects
) AS P
INNER JOIN ProjectData PD
ON P.ProjectID = PD.ProjectID

Depending on your version of SQL Server you can use CROSS APPLY to UNPIVOT the data.
CROSS APPLY and VALUES will work in SQL Server 2008+:
select name,
ProjectId
from yourtable
cross apply
(
values
('Project_One_ID', Project_One_ID),
('Project_Two_ID', Project_Two_ID),
('Project_Three_ID', Project_Three_ID)
) c (col, ProjectId);
If you are using SQL Server 2005, then you can use CROSS APPLY with UNION ALL:
select name,
ProjectId
from yourtable
cross apply
(
select 'Project_One_ID', Project_One_ID union all
select 'Project_Two_ID', Project_Two_ID union all
select 'Project_Three_ID', Project_Three_ID
) c (col, ProjectId)

if name is a foreign key (unusual - but i suppose possible)
then you could union these things together..
select name, project_one_id as project_id
from newtable
union
select name, project_two_id
from newtable
union
select name, project_three_id
from newtable

The most efficient way to write this query is as an unpivot. This only scans the table once. Here is an example:
with t as (select 'a' as name, 1 as project_one, 2 as project_two, 3 as project_three)
select name, project
from t
unpivot (project for col in (project_one, project_two, project_three)) as unpvt
You can put the unpivot in a view for easy access or use it to create a new table with the columns you want.

Related

How to add union data in table?

Thanks in advance !!
I want to get below data in separate table with column how can we achieved this.
From my reading of your question, you would like the results of that SELECT statement put into a new table?
Firstly, I'm assuming your original SQL works as a SELECT statement - e.g., all those tables have the same structure. Note that you can simplify the unions, but I haven't done so here, to keep the key part of the answer (saving the data) as the main focus.
To save the data into another table, you can either create a table first and make that into an insert, or just use 'SELECT INTO' within the main SELECT.
If you are happy with the columns being automatically created, the 'SELECT INTO' version will create columns (e.g., you do not need to specify the columns in a CREATE TABLE statement). However, when you run the SELECT INTO, it does create the table. Therefore if you want to insert further values, you need to specify the column list (or have matching column lists).
SELECT INTO version
select *
INTO #Temp -- Added This row
from
( select * from #OneyearExpiry
union all
select * from #OtherYearExpiry
) A
except
select * from
( select * from #ONEYRCON
union all
select * from #OTHERYRCON
) B
INSERT INTO version
CREATE TABLE #Temp (<your fields here to match the SELECT statement>)
INSERT INTO #Temp
select * from
( select * from #OneyearExpiry
union all
select * from #OtherYearExpiry
) A
except
select * from
( select * from #ONEYRCON
union all
select * from #OTHERYRCON
) B
Set operators are evaluated from top to bottom so there only needs to be 1 subquery. Something like this
select ab.* into #Temp
from (select * from #OneyearExpiry
union all
select * from #OtherYearExpiry
except
select * from #ONEYRCON
except
select * from #OTHERYRCON) ab;

Order two parts of a union independently of one another

Is it possible to do something like this:
select name from table1 order by name
union
select name from table2 order by name
I know I can do this:
select name from table1
union
select name from table2 order by name
However, I want the names from table1 to appear first. I have spent the last hour Googling this and I have go nowhere. For example, I have looked here: How to order by with union in SQL?
The query needs to be a bit more complicated:
select name
from ((select distinct name, 1 as is_1 from table1)
union
(select distinct name, 0 from table2)
) n
group by name
order by max(is_1), name;
This uses select distinct in the subqueries because that can take advantage of an index on name.
Add a "sort" field and put the union inside a subquery so you can sort after the union.
untested
select a.name
from (
select name, 1 sort
from table1
union all
select name, 2 sort
from table2
) a
order by a.sort, a.name
I changed it to union all to make it clear this approach won't do a union. You could also select the sort column if you want to see it. If you don't want duplicate names, then this approach won't work.
You need another column to sort on. UNION does not allow the individual queries to have an ORDER BY clause.
Adding in a column to sort on before name allows for it to sort the individual result sets. See my example below:
CREATE TABLE #Table1 (Name VARCHAR(50))
CREATE TABLE #Table2 (Name VARCHAR(50))
INSERT INTO #Table1 VALUES ('Bart'), ('Lisa'), ('Maggie')
INSERT INTO #Table2 VALUES ('Chris'), ('Meg'), ('Stewie')
SELECT Name, 0 AS Sort FROM #Table1
UNION
SELECT Name, 1 AS Sort FROM #Table2
ORDER BY Sort, Name

Distinct values from two columns

This is the query which I am using to get the distinct values:
SELECT DISTINCT
LOGIN_BY,
RECEIVED_BY
FROM SAMPLE
My requirement is I need the distinct values of both the columns as a single output. Is there any way to do that?
try this
(SELECT DISTINCT LOGIN_BY as ID from sample )
union all
(Select Distinct RECEIVED_BY as ID FROM SAMPLE)
Try it like this:
select distinct a from (
select
distinct LOGIN_BY as a
from
SAMPLE
union
select
distinct RECEIVED_BY as a
from
SAMPLE
);
This works for me on an Oracle database.

How to find a record from more than one table in SQL

I have two table containing some information as below
ENRNO, PROGRAM, NAME, ADDRESS, AGE
I want to find data referencing ENRNO which is containing from one of the given table but I don't know which table have the information.
Please suggest.
Malay Barik
If ENRNO is unique in tables u may try use UNION
select * from t1
where ENRNO ='ENRNO1'
UNION select * from t2
where ENRNO ='ENRNO1'
else use DISTINCT and subquery
select DISTINCT * from (
select * from t1
where ENRNO ='ENRNO1'
UNION select * from t2
where ENRNO ='ENRNO1')
But goodest way for solving this is redesign(normalize) you DB.

UNION operation with the same table

I have a scenario where I need to query data in a single row as multiple columns,
Table format is as follows,
SAMPLE_TABLE [ID, REF_TAB_A,REF_TAB_B,REF_TAB_C]
I need REF_TAB_A,REF_TAB_B,REF_TAB_C values in a single column. What I did is use UNION ALL as follows,
SELECT REF_TAB_A FROM SAMPLE_TABLE
UNION ALL
SELECT REF_TAB_B FROM SAMPLE_TABLE
UNION ALL
SELECT REF_TAB_C FROM SAMPLE_TABLE
Is there any other way to do this?? What is the most efficient way to handle such a scenario??
(I'm using oracle 11g)
Thanks in advance.. :D
Using union all generally results in three scans of the table. An alternative approach is a little messier but should have just one scan:
SELECT (case when which = 'A' then REF_TAB_A
when which = 'B' then REF_TAB_B
when which = 'C' then REF_TAB_C
end)
FROM SAMPLE_TABLE cross join
(select 'A' as which from dual union all select 'B' from dual union all select 'C' from dual
) iter
You could alias the columns:
SELECT REF_TAB_A tab FROM SAMPLE_TABLE
UNION ALL
SELECT REF_TAB_B tab FROM SAMPLE_TABLE
UNION ALL
SELECT REF_TAB_C tab FROM SAMPLE_TABLE
What you really need to do, however, is to normalize your database. Whenever you have columns with repeating names like name1, name2, name3, namea, nameb, and namec, it is a sign that you want another table and a 1-many relationship between them.
CREATE TABLE tabs (
tab_id NUMBER PRIMARY KEY,
sample_table_id NUMBER,
tab VARCHAR2(255),
CONSTRAINT FK_sample_table
FOREIGN KEY(sample_table_id)
REFERENCES SAMPLE_TABLE(sample_table_id)
)
Now your query involves a simple JOIN.
SELECT
tab
FROM tabs t
JOIN SAMPLE_TABLE st ON t.sample_table_id = st.sample_table_id
WHERE
...
As an alternative to Gordon's CROSS JOIN trick Oracle has the UNPIVOT clause in the SELECT statement specifically for this situation.
Assuming this table:
create table tmp_test ( a number, b number, c number );
insert all
into tmp_test values (1,2,3)
into tmp_test values (4,5,6)
select * from dual;
The following query would do what you require:
select col
from tmp_test
unpivot ( col for i in (a,b,c) );
COL
----------
1
2
3
4
5
6
6 rows selected.
For this small example an explain plan indicates that using the inbuilt functionality would be more efficient but but test both options and see what's better.