Rows as Columns without Join - sql

Please have a look at this. The result shows, indeed, a join of two sets. I want the output as following i.e. No Cartesian Product.
ID_1 TYPE_1 NAME_1 ID_2 TYPE_2 NAME_2
===============================================================
TP001 1 Adam Smith TV001 2 Leon Crowell
TP002 1 Ben Conrad TV002 2 Chris Hobbs
TP003 1 Lively Jonathan
I used one of the solution, join, known to me to select rows as columns but i need results in required format while join is not mandatory.

You need an artificial column as id. Use rownum for that on both types of teachers.
Because you do not know if there are more Teachers of type 1 or of Type 2, you must do a full outer join to combine both sets.
SELECT *
FROM (SELECT ROWNUM AS cnt, teacherid
, teachertype, teachername
FROM teachers
WHERE teachertype = 1) qry1
FULL OUTER JOIN (SELECT ROWNUM AS cnt, teacherid
, teachertype, teachername
FROM teachers
WHERE teachertype = 2) qry2
ON qry1.cnt = qry2.cnt
In general, databases think in rows, not in columns. In your example you are lucky - you only have two types of teachers. For every new type of teacher you would have to alter your statement and append a full outer join only to present the output of your query in a special way - one set per column.
But with a simple select you retrive the same Information and it will work regardless how many teacher types you have.
SQL is somewhat limited in presenting data, i would leave that to the client retriving the data or use PL/SQL for a more generic aproach.

There should be some constraint of keys on which you join table or tables. If there is no constraint it will always result in Cartesian Product i.e number of rows of first table x numbers of rows of second table

SELECT TONE.TEACHERID ID_1, TONE.TEACHERTYPE TYPE_1, TONE.TEACHERNAME NAME_1
,TTWO.TEACHERID ID_2, TTWO.TEACHERTYPE TYPE_2, TTWO.TEACHERNAME NAME_2
FROM
(SELECT TEACHERID, TEACHERTYPE, TEACHERNAME FROM TEACHERS WHERE TEACHERTYPE = 1)
TONE
FULL OUTER JOIN
(SELECT TEACHERID, TEACHERTYPE, TEACHERNAME FROM TEACHERS WHERE TEACHERTYPE = 2)
TTWO
ON TONE.TEACHERID = REPLACE(TTWO.TEACHERID,'TV','TP');
ID_1 TYPE_1 NAME_1 ID_2 TYPE_2 NAME_2
===== ====== ====== ====== ====== ======
TP001 1 Adam Smith TV001 2 Leon Crowell
TP002 1 Ben Conrad TV002 2 Chris Hobbs
TP003 1 Lively Jonathan (null) (null) (null)
http://www.sqlfiddle.com/#!4/c58f3/28

Related

SQL Query to retrive translated value in output

i have a position table
pos_table with column
position_code job_code location_code pos_name BUSINESS_UNIT
1 staff delhi supervisor XYZ
2 supervor manila technical associate ABC
mapping table
table_code source_code business_unit target_code
LOC DELHI XYZ 10
loc MANILA ABC 20
job staff XYZ 01
job supervisor ABC 02
I want a query which joins mapping table and pos_table such that
for job_code staff in the output 01 from mapping table target_code should come
using business_unit and source_code as join.
output:
position_code job_code location_code pos_name BUSINESS_UNIT
1 01 10 supervisor XYZ
2 02 20 technical associate ABC
for this i wrote the query :
select POSITION_CODE,
coalesce(JOB_MAP.FUSION_HARMONIZED_CODE,JOB_CODE) JOB_CODE,
coalesce(LOC_MAP.FUSION_HARMONIZED_CODE,LOCATION_CODE)LOCATION_CODE
from pos_tab POS_STAG,
MAPPING_TAB LOC_MAP,
mapping_tab job_MAP
where 1=1
and JOB_MAP.source_code||business_unit_name = POS_STAG.JOB_CODE||business_unit_name
and LOC_MAP.TABLE_CODE ='LOC'
and job_map.table_code='JOB'
and LOC_MAP.source_code ||business_unit_name = POS_STAG.LOCATION_CODE||business_unit_name;
but this is not working and it is rerieving more number of rows
I'm not sure what "SOURCE_CORE_HR_CODE" is since you don't explain it in your question but I'm guessing the below is correct.
The problem is you are using your mapping table for two different joins so you have to join it twice.
I'm using the "new" joining syntax which has existed as a standard for over 20 years. I suggest you using this syntax. It is much easier to understand how SQL works using this syntax. I've no idea why anyone would use the old style.
SELECT P.POSITION_CODE, M1.TARGET_CODE AS JOB_CODE, M2.TARGET_CODE AS LOCATION_CODE, P.JOB_CODE AS POS_NAME, P.BUSINESS_UNIT
FROM POS_TABLE P
JOIN MAPPING_TABLE M1 ON P.JOB_CODE = M1.SOURCE_CODE AND upper(M1.TABLE_CODE) = 'JOB'
JOIN MAPPING_TABLE M2 ON P.BUSINESS_UNIT = M2.BUSINESS_UNIT AND upper(M2.TABLE_CODE) = 'LOC'

More efficient SQL statement to eliminate my n^2 algorithm?

Let's say the following are my SQL tables:
My first table is called [Customer].
CustomerID CustomerName CustomerAddress
---------- ------------ ---------------
1 Name1 1 Infinity Loop
2 Name2 2 Infinity Loop
3 Name3 3 Infinity Loop
My next table is called [Group].
GroupID GroupName
------- ---------
1 Group1
2 Group2
3 Group3
Then, to link the two, I have a table called [GroupCustomer].
GroupID CustomerID
------- ----------
1 2
1 3
2 1
3 1
So on the ASP.NET page, I have two tables I want to display. The first table are essentially all Customers that are in a particular group. So in a drop down list, if I select Group1, it would display the following table:
CustomerID CustomerName CustomerAddress
---------- ------------ ---------------
2 Name2 2 Infinity Loop
3 Name3 3 Infinity Loop
The table above is for all customers that are "associated" with the selected group (which in this case is Group1). Then, in the other table, I want it to display this:
CustomerID CustomerName CustomerAddress
---------- ------------ ---------------
1 Name1 1 Infinity Loop
Essentially, for this table, I want it to display all customers that are NOT in the selected group.
To generate the table for all customers that are in the selected group, I wrote the following SQL:
SELECT Customer.CustomerID, Customer.CustomerName, Customer.CustomerAddress
FROM Customer
INNER JOIN GroupCustomer ON
Customer.CustomerID = GroupCustomer.CustomerID
INNER JOIN [Group] ON
GroupCustomer.GroupID = [Group].GroupID
WHERE [Group].GroupID = #selectedGroupParameter
So when I mentioned my n^2 algorithm, I essentially used the SQL statement above, and compared it against a SQL statement where I just SELECT * from the Customer table. Where there was a match, I just simply had it did not display it. This is incredibly inefficient, and something I'm not proud of.
This leads to my current question, what's the most efficient SQL statement I can write that will eliminate my n^2?
You can use NOT EXISTS to get Customers not in a particular Group:
SELECT *
FROM Customer c
WHERE
NOT EXISTS(
SELECT 1
FROM GroupCustomer
WHERE
CustomerID = c.CustomerID
AND GroupID = #selectedGroupParameter
)
Read this article by Aaron Bertrand for different ways to solve this kind of problem and their performance comparisons, with NOT EXISTS being the fastest according to his test.
SQL Fiddle
Select * from Customer
where CustomerID not in
(select CustomerID
from GroupCustomer
where GroupID = #selectedGroupParameter)
You can use not in for this check. That said, you can probably just get rid of the join to the Group table for some increased performance, since you don't appear to actually use the group name.

sql merge tables side-by-side with nothing in common

I'm looking for an sql answer on how to merge two tables without anything in common.
So let's say you have these two tables without anything in common:
Guys Girls
id name id name
--- ------ ---- ------
1 abraham 5 sarah
2 isaak 6 rachel
3 jacob 7 rebeka
8 leah
and you want to merge them side-by-side like this:
Couples
id name id name
--- ------ --- ------
1 abraham 5 sarah
2 isaak 6 rachel
3 jacob 7 rebeka
8 leah
How can this be done?
I'm looking for an sql answer on how to merge two tables without anything in common.
You can do this by creating a key, which is the row number, and joining on it.
Most dialects of SQL support the row_number() function. Here is an approach using it:
select gu.id, gu.name, gi.id, gi.name
from (select g.*, row_number() over (order by id) as seqnum
from guys g
) gu full outer join
(select g.*, row_number() over (order by id) as seqnum
from girls g
) gi
on gu.seqnum = gi.seqnum;
Just because I wrote it up anyway, an alternative using CTEs;
WITH guys2 AS ( SELECT id,name,ROW_NUMBER() OVER (ORDER BY id) rn FROM guys),
girls2 AS ( SELECT id,name,ROW_NUMBER() OVER (ORDER BY id) rn FROM girls)
SELECT guys2.id guyid, guys2.name guyname,
girls2.id girlid, girls2.name girlname
FROM guys2 FULL OUTER JOIN girls2 ON guys2.rn = girls2.rn
ORDER BY COALESCE(guys2.rn, girls2.rn);
An SQLfiddle to test with.
Assuming, you want to match guys up with girls in your example, and have some sort of meaningful relationship between the records (no pun intended)...
Typically you'd do this with a separate table to represent the association (relationship) between the two.
This wouldn't give you a physical table, but it would enable you to write an SQL query representing the final results:
SELECT Girls.ID AS GirlId, Girls.Name AS GirlName, Guys.ID AS GuyId, Guys.Name AS GuyName
FROM Couples INNER JOIN
Girls ON Couples.GirlId = Girls.ID INNER JOIN
Guys ON Couples.GuyId = Guys.ID
which you could then use to create a table on the fly using the Select Into syntax
SELECT Girls.ID AS GirlId, Girls.Name AS GirlName, Guys.ID AS GuyId, Guys.Name AS GuyName
INTO MyNewTable
FROM Couples INNER JOIN
Girls ON Couples.GirlId = Girls.ID INNER JOIN
Guys ON Couples.GuyId = Guys.ID
(But standard Normalization rules would say it's best to keep them in distinct tables rather than creating a temp table, unless there's a performance reason not to do so.)
I need this all the time, -- creating templates in Excel using input from my tables. This pulls from one table that has my regions, the other with the quarters in a year. the result gives me one region name for each quarter/period.
SELECT b.quarter_qty, a.mkt_name FROM TBL_MKTS a, TBL_PERIODS b

write a query to identify discrepancy

I have a table with Student ID's and Student Names. There has been issues with assigning unique Student Id's to students and Hence I want to find the duplicates
Here is the sample Table:
Student ID Student Name
1 Jack
1 John
1 Bill
2 Amanda
2 Molly
3 Ron
4 Matt
5 James
6 Kathy
6 Will
Here I want a third column "Duplicate_Count" to display count of duplicate records.
For e.g. "Duplicate_Count" would display "3" for Student ID = 1 and so on. How can I do this?
Thanks in advance
Select StudentId, Count(*) DupCount
From Table
Group By StudentId
Having Count(*) > 1
Order By Count(*) desc,
Select
aa.StudentId, aa.StudentName, bb.DupCount
from
Table as aa
join
(
Select StudentId, Count(*) as DupCount from Table group by StudentId
) as bb
on aa.StudentId = bb.StudentId
The virtual table gives the count for each StudentId, this is joined back to the original table to add the count to each student record.
If you want to add a column to the table to hold dupcount, this query can be used in an update statement to update that column in the table
This should work:
update mytable
set duplicate_count = (select count(*) from mytable t where t.id = mytable.id)
UPDATE:
As mentioned by #HansUp, adding a new column with the duplicate count probably doesn't make sense, but that really depends on what the OP originally thought of using it for. I'm leaving the answer in case it is of help for someone else.

mysql select in two tables

I have two tables and one reference table for the query. Any suggestion or help would greatly appreciated.
table1
user_id username firstname lastname address
1 john867 John Smith caloocan
2 bill96 Bill Jones manila
table2
user_name_id username firstname lastname address designation
1 jakelucas Jake Lucas caloocan employee
2 jadejones Jade Jones Quezon student
3 bong098 Bong Johnson pasig employee
reference table
ref_id username friend_username
1 tirso bill96
2 tirso jadejones
2 tirso bong098
the output should like this
user_id user_name_id username firstname lastname address designation
2 bill96 Bill Jones manila
2 jadejones Jade Jones Quezon student
3 bong098 Bong Johnson pasig employee
Since some decent union queries have already been posted, I'll talk about your db design a little bit.
I would definitely take what IronGoofy said into serious consideration before you take too much time looking into joining these tables together. It seems that you have a lot of duplicate data to manage with your tables, and that could get out of hand rather quickly should this scale up.
I think you should probably try and separate your data out so that the important information can be linked on the user_id.
So, for instance, you could have a few tables here...
User Information Table:
---------
User_id
Username
First Name
Last Name
Address
Designation_id
Friend Link Table:
---------
Friend_link_id
User_id
Friend_user_id
Designation Table:
---------
Designation_id
Designation_name
So, rather than link on your user names all over the place, you would simply join on the various ID's. A bit cleaner and missing the duplicate data issue that you had before IMO. Hope this helps...
Can you try something like this
SELECT [table1].[USER_ID],
NULL user_name_id,
[table1].username,
[table1].firstname,
[table1].lastname,
[table1].address,
NULL designation
FROM reference_table INNER JOIN
table1 ON [reference_table].friend_username = [table1].username
UNION
SELECT NULL USER_ID,
[table2].user_name_id,
[table2].username,
[table2].firstname,
[table2].lastname,
[table2].address,
[table2].designation
FROM reference_table INNER JOIN
table2 ON [reference_table].friend_username = [table2].username
It's not quite clear what you are trying to achieve, but here's a guess:
SELECT user_id, NULL as user_name_id, username, ...
FROM ref_tab r join table1 t1 on r.friend_username = t1.username
WHERE r.ref_id = 1
UNION
SELECT NULL as user_id, user_name_id, username, ...
FROM ref_tab r join table1 t2 on r.friend_username = t2.username
WHERE r.ref_id = 2
But I'd have a hard look at the DB design and think about some improvements ...