MySQL combine row results into a new column - sql

I am trying to set up a query to return data to a VB.Net datagrid. I want to rollup the results into a new column kinda like below:
For example on Match-no:
Date Sponsor Match_no Team
---------------------------------------
1-1-11 Nike 1 Tigers
1-1-11 Nike 1 Bears
2-1-11 Crisco 2 Llamas
2-1-11 Crisco 2 Tigers
Roll it up into a new column.
Date Sponsor Match_no Teams_playing
---------------------------------------------------
1-1-11 Nike 1 Tigers vs Bears
2-1-11 Crisco 2 Llamas vs Tigers
I tried using "group_concat" but for some reason it rolled up the entire list on teams into a column regardless of match_no.
In this example there would be 4 tables :
Dates Sponsors Match Team
------ -------- ------- --------
Date_id Sponsor_id Match_id Team_id
Date Sponsor_name Match_no Team_name
Sponsor_id Match_id

Try:
SELECT m.date,
m.sponsor,
m.match_no,
GROUP_CONCAT(m.team, SEPARATOR ' vs ')
FROM MATCH_NO m
GROUP BY m.date, m.sponsor, m.match_no

Your table structure looks suspicious. Dates has no correspondence to Match. Team should be in a separate table with a bridge:
match_team
-----------
match_id
team_id
Or if there are only ever going to be two teams per match, then just
match
---------
match_id
Match_no
sponsor_id
date_id
team_id_a
team_id_b
Normally, one would not create a date table with just id and date, e.g. it doesn't help indexing or searching on the Match table by date.
For your original question, the query would be
select d.date, s.sponsor_name, m.match_no,
group_concat(teams_playing separator ' vs ') Teams_playing
from match m
inner join dates d on d.date_id = m.date_id
inner join sponsors s on s.sponsor_id = m.sponsor_id
inner join team t on t.match_id = m.match_id
group by m.match_id, d.date, s.sponsor_name, m.match_no
Ref: GROUP_CONCAT

Related

How can I count unique attribute values using two attributes and joining two tables?

I'm a beginner in SQL.
Simplified, I have two tables, districts and streetdistricts, which contain information about city districts and streets. Every district has a unique number dkey and every street has a unique street number stkey (as primary keys respectively).
Here's an example:
Table districts:
dkey
name
1
Inner City
2
Outer City
3
Outskirts
Table streetdistricts:
stkey
dkey
113
1
126
2
148
2
148
3
152
3
154
3
What I want to do now is to find out how many streets are there per district that are located only in one single district. So that means I do not have to just remove duplicates (like street with stkey 148 here), but instead to remove streets that are situated in more than one district completely so that I only see the districts and the number of streets per district that are just located in one district only.
For this example, this would be:
name number_of_street_in_just_this_district
Inner City 1
Outer City 1
Outskirts 2
I've tried many things, but I always get stuck, mostly because when I SELECT the name of the district, it is also needed in GROUP BY as SQL says, but when I add it, then either the whole number of streets (here: 6) or at least the number including the duplicates (here: 5) are displayed, but not the right answer of 3.
Or I'm not able to JOIN the tables correctly so to get the output I want. Here is my last try:
SELECT SUM(StreetDistricts.dkey) as d_number, StreetDistricts.stkey, COUNT(StreetDistricts.stkey) as numb
FROM StreetDistricts
INNER JOIN Districts ON Districts.dkey = StreetDistricts.dkey
GROUP BY StreetDistricts.stkey
HAVING COUNT(StreetDistricts.dkey) = 1
ORDER BY d_number DESC
This works to get me the correct sum of rows, but I was not able to combine/join it with the other table to receive name and number of unique streets.
First obtain the streets that are found in only one district (cte1). Then count just those streets per district. This should do it:
WITH cte1 AS (
SELECT stkey FROM StreetDistricts GROUP BY stkey HAVING COUNT(DISTINCT dkey) = 1
)
SELECT d.name, COUNT(*) AS n
FROM StreetDistricts AS s
JOIN Districts AS d
ON s.dkey = d.dkey
AND s.stkey IN (SELECT stkey FROM cte1)
GROUP BY d.dkey
;
Result:
+------------+---+
| name | n |
+------------+---+
| Inner City | 1 |
| Outer City | 1 |
| Outskirts | 2 |
+------------+---+
Note: I used the fact that dkey is the primary key of Districts to avoid having to GROUP BY d.name as well. This is guaranteed by functional dependence. If your database doesn't guarantee that with a constraint, just add d.name to the final GROUP BY terms.
The test case:
CREATE TABLE Districts (dkey int primary key, name varchar(30));
CREATE TABLE StreetDistricts (stkey int, dkey int);
INSERT INTO Districts VALUES
(1,'Inner City')
, (2,'Outer City')
, (3,'Outskirts')
;
INSERT INTO StreetDistricts VALUES
(113,1)
, (126,2)
, (148,2)
, (148,3)
, (152,3)
, (154,3)
;

Sqlite - get the most recent record per table

I am keeping track of people changing their names. I have three tables:
TableOne
id
1
2
TableTwo
Date id FirstName NameID
01/02/2016 1 TestOne 1
01/03/2017 2 TestTwo 2
01/04/2015 3 TestThree 1
TableThree
Date id SecondName NameID
01/01/2016 1 TestThree 1
01/01/2018 2 TestFour 1
01/10/2014 3 TestFive 2
The NameIDs in tables 2 & 3 map to the id in table 1. Every time a person changes their first name I add a record to table 2 and every time a person changes their second name I add a record to table 3. I keep list of all their historical names.
My aim is to use a SELECT query to pull back what each person's name today is i.e. I need to SELECT the most recent pair of names for each unique id in table 1.
My end table should look like this:
NameID FirstName SecondName
1 TestOne TestFour
2 TestTwo TestFive
I can get the most recent firstnames and secondnames as follows:
SELECT FirstName, MAX(Date) FROM TableTwo GROUP BY NameID;
SELECT SecondName, MAX(Date) FROM TableOne GROUP BY NameID;
But how can I put these 2 queries together? (Sorry if easy question - I am quite new to this and please let me know if anything unclear at all - thanks in advance!)
Use correlated subqueries to lookup the corresponding names:
SELECT id,
(SELECT FirstName
FROM TableTwo
WHERE NameID = TableOne.id
ORDER BY Date DESC
LIMIT 1
) AS FirstName,
...
FROM TableOne;

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'

Return all dates that do not have a matching entry

I've tried some of the other solutions I've found on SO, but they don't seem to work with my schema, or I just suck at SQL. So let's say I have two tables, table 1 is something like this:
LastName | FirstName | Date
Doe John 7/07/14
Doe John 7/07/14
Doe John 7/08/14
Bond James 7/07/14
Bond James 7/09/14
Jane Mary 7/08/14
Essentially, a person will have an entry for a certain date. they can also have multiple entries for one date. table 2 is a range of dates, such as:
Date
7/06/14
7/07/14
7/08/14
7/09/14
What I want to do is get a result set that shows for what days in table 2 is a person missing an entry, ideally with the person's name as well. Any leads? Thanks!
Try this,
;WITH CTE AS
(
--create list of all names and date combinations from both table
SELECT DISTINCT A.LastName, A.FirstName, B.Date_col
FROM Table1 A, Table2 B
)
--select rows that are missing dates in your first table
SELECT X.* FROM CTE X
LEFT OUTER JOIN Table1 Y
ON X.LastName = Y.LastName
AND X.FirstName = Y.FirstName
AND X.Date_col = Y.Date_Col
WHERE Y.LastName IS NULL

Rows as Columns without Join

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