Table 1 has, the NameId, age, gender...
Table 2 has Version No, TimeStamp ...
Now I want to select the NameId from Table 1, and Version No. and Timestamp multiple times from table 2, i need to query all the Version and Time records from table2,
can anyone give me some idea about how to query?
NameId | Version/Time | Version/Time | Version/Time …
Angela | 1 / 01.01.2010 | 2 / 01.02.2010 | 3 / 01.03.2010
Betty | 1 / 01.01.2010 | 2 / 01.02.2010 | 3 / 01.03.2010
Cathy | 1 / 01.01.2010 | 2 / 01.02.2010 | 3 / 01.03.2010
... | .... | |
if, as you say, any fixed value set won't work, then you'll need dynamic sql to do your pivot.
something along these lines:
CREATE PROCEDURE [dbo].[usp_pivot_]
AS
DECLARE #columns VARCHAR(1000)
SELECT #columns = COALESCE(#columns + ',[' + cast(versionTime as varchar) + ']',
'[' + cast(versionTime as varchar)+ ']')
FROM table1 inner join table2 on table1.NameId = table2.NameId
GROUP BY versionTime
DECLARE #query VARCHAR(8000)
SET #query = '
SELECT *
FROM table1 inner join table2 on table1.NameId = table2.NameId
PIVOT
(
first(versionTime)
FOR [versionTime]
IN (' + #columns + ')
)
AS p'
EXECUTE(#query)
The usual approach is performing a JOIN between the two tables, e.g.
SELECT t1.NameId
, t2.VersionNo
, t2.Timestamp
FROM table_one t1
LEFT
JOIN table_two t2
ON t2.NameId = t1.NameId
ORDER
BY t1.NameId
, t2.VersionNo
That will get you a result set like:
NameId VersionNo TimeStamp
-------- --------- ----------
Angela 1 01.01.2010
Angela 2 01.02.2010
Angela 3 01.03.2010
Betty 1 01.01.2010
Betty 2 01.02.2010
Betty 3 01.03.2010
Cathy 1 01.01.2010
Cathy 2 01.02.2010
Cathy 3 01.03.2010
(This assumes that table_two is related to table_one by the NameId value. The sample data provided in the original question leaves open the possibility that this is three rows in table_two matched with each row in table_one (i.e. a Cartesian product). In that case, it would be a CROSS JOIN in the statement:
SELECT t1.NameId
, t2.VersionNo
, t2.Timestamp
FROM table_one t1
CROSS
JOIN table_two t2
ORDER
BY t1.NameId
, t2.VersionNo
To get the resultset from that query converted into a "crosstab" (or pivot table), with each separate row from table_two displayed in the same line of output, that is usually better handled in the client, rather than in the SQL statement.
However, it is possible for MySQL to return a similar resultset, with each VersionNo and Timestamp value in a separate column; but the query to do that is non-trivial.
(One trivial alternative is to use the GROUP_CONCAT aggregate function, but that returns a single column, not separate columns, and is limited by max_allowd_packet_size.)
SELECT t1.NameID
, GROUP_CONCAT(CONCAT(t2.VersionNo,'/',t2.Timestamp) ORDER BY t2.VersionNo)
FROM table_one t1
LEFT
JOIN table_two t2
ON t2.NameId = t1.NameId
GROUP
BY t1.NameId
ORDER
BY t1.NameId
Again assuming that table_two is related to table_one, one rather unwieldy, but easily understandable, approach is to use correlated subqueries in the SELECT list of the query, e.g.
SELECT t1.NameId
, ( SELECT CONCAT(t2a.VersionNo,' / ',t2a.Timestamp)
FROM table_two t2a WHERE t2a.NameId = t1.NameID
ORDER BY t2a.VersionNo LIMIT 0,1
) AS `Version/Time`
, ( SELECT CONCAT(t2b.VersionNo,' / ',t2b.Timestamp)
FROM table_two t2b WHERE t2b.NameId = t1.NameID
ORDER BY t2b.VersionNo LIMIT 1,1
) AS `Version/Time`
, ( SELECT CONCAT(t2c.VersionNo,' / ',t2c.Timestamp)
FROM table_two t2c WHERE t2c.NameId = t1.NameID
ORDER BY t2c.VersionNo LIMIT 2,1
) AS `Version/Time`
FROM table_one t1
ORDER BY t1.NameId
That query will return a resultset similar to the one shown in the original question, although the number of columns returned is statically defined within SELECT the statement.
Related
Goal:
Trying to join together two tables
Table structure:
t1:
name | id
t2:
id_a | id_b | id_c | id_d | favorite color
Problem:
I'm trying to find out the favorite color that corresponds to each name, where the t1.id is found in 1 of the 4 id fields in t2. The tricky part is that the non-matching values aren't null, so a coalesce doesn't work.
What I've tried:
Tried a case when statement in the join, but that seems to be creating some endless loop that is never finishing.
Trying a union, but that is creating some unexpected duplication.
Also tried a multi- on condition (like below), but that's not working:
WITH test AS (
SELECT
t1.*
, t2.*
FROM t1
LEFT JOIN t2
ON ( t1.id = t2.id_a
OR t1.id = t2.id_b
OR t1.id = t2.id_c
OR t1.id = t2.id_d
)
)
SELECT COUNT(*) FROM test
;
Here's an example dataset:
WITH names AS(
SELECT
1 as id , 'alfred' as name
UNION ALL SELECT 2, 'becca'
UNION ALL SELECT 3, 'charlie'
UNION ALL SELECT 4, 'dezi'
)
, color AS(
SELECT
1 as id_a, 6 as id_b, 9 as id_c, 7 as id_d, 'green' as fave_color
UNION ALL SELECT 1,2,6,5, 'orange'
UNION ALL SELECT 5,7,9,3, 'blue'
UNION ALL SELECT 9,4,6,8, 'black'
)
SELECT
n.id
, n.name
, c.fave_color
FROM color c
LEFT JOIN names n
ON n.id IN (c.id_a,c.id_b,c.id_c,c.id_d)
GROUP BY 1,2,3
ORDER BY 1,2
;
I have 1:N table where every entity may have asigned multiple numbers.
ID Number
1 10
1 13
1 11
1 12
1 16
2 11
2 12
2 13
2 10
Now,I want all IDs which have for example 3 numbers in ascending sequence. I do not specify which numbers I want, I just want the SQL to return me all possible combinations it can find but the numbers has to be in ascending sequence and the sequence must contain exactly 3 numbers. The numbers are allways integers of any value. The numbers in result have to be next to each other (12,13,16)is not valid result.
For 3 numbers in this example it would be :
ID 1 : (10,11,12),(11,12,13)
ID 2 : (11,12,13),(10,11,13)
For 2 numbers in this example it would be:
ID 1 : (10,11),(11,12),(12,13)
ID 2 : (11,12)(12,13)
Is this possible in SQL select? Thanx
A solution whats comes close to your expected output.
Involves using self inner joins incombination with CONCAT_WS, GROUP_CONCAT..
For group of three you use this query
Query
SET SESSION group_concat_max_len = ##max_allowed_packet
SELECT
records.ID
, GROUP_CONCAT(CONCAT('(', records.number, ')'))
FROM (
SELECT
DISTINCT
table11.ID
, CONCAT_WS(
','
, table11.Number
, table12.Number
, table13.Number
) AS number
FROM
Table1 AS table11
INNER JOIN
Table1 AS table12
ON
table11.Number + 1 = table12.Number
INNER JOIN
Table1 table13
ON
table12.Number + 1 = table13.Number
ORDER BY
table11.ID ASC
, table11.Number ASC
) AS records
GROUP BY
records.ID
Result
| ID | GROUP_CONCAT(CONCAT('(', records.number, ')')) |
|----|------------------------------------------------|
| 1 | (11,12,13),(10,11,12) |
| 2 | (11,12,13),(10,11,12) |
see demo http://sqlfiddle.com/#!9/c5dfce/39
Simply use join. This produces a result set with each examples of sequential numbers on a different row:
select id, t1.number, t2.number, t3.number
from t t1 join
t t2
on t2.id = t1.id and t2.number = t1.number + 1 join
t t3
on t3.id = t2.id and t3.number = t2.number + 1;
If you really wanted a list, you would simply do:
select id,
group_concat('(', t1.number, ',', t2.number, ',', t3.number, ')') as groups
from t t1 join
t t2
on t2.id = t1.id and t2.number = t1.number + 1 join
t t3
on t3.id = t2.id and t3.number = t2.number + 1
group by t1.id;
Table 1
ID | NAME | WARD_ID|
1 A 1
2 B 1
3 C 2
4 D 2
Table 2
ID | MONTH1 | MONTH2 | WARD_ID|
1 9 10 1
2 6 11 1
3 5 12 2
4 13 14 2
I want to join this two table and produce the following output:
ID | NAME | MONTH1 | MONTH2 | WARD_ID|
1 A 9 10 1
2 B 6 11 1
3 C 5 12 2
4 D 13 14 2
In the ON condition of the query I have to keep WARD_ID equal for both the tables. I could not able to figure out the solution. Anyone have any experience with a query like this?
I think you want something like this:
select t1.*, t2.*
from (select t1.*,
(#rn1 := if(#w1 = ward_id, #rn1 + 1,
if#w1 := ward_id, 1, 1)
)
) as rn
from (select t1.* from table1 t1 order by ward_id, id ) t1 cross join
(select #w1 := -1, #rn1 := -1) params
) t1 join
(select t2.*,
(#rn2 := if(#w2 = ward_id, #rn2 + 1,
if#w2 := ward_id, 1, 1)
)
) as rn
from (select t2.* from table2 t2 order by ward_id, id ) t2 cross join
(select #w2 := -1, #rn1 := -1) params
) t1
on t2.ward_id = t1.ward_id and t2.rn = t1.rn;
The subqueries enumerate the rows in each table. The join then uses the enumeration.
This is much simpler in MySQL 8.0, using row_number().
I'm assuming here that ID is intended to be the same from both tables. If so, I think you can do a multi-condition join:
select * from table1 t1
inner join table2 t2
on t1.ID=t2.ID and t1.WARD_ID=t2.WARD_ID
You can do something like:
SET #rn:=0;
SET #rn2:=0;
SELECT *
FROM (
SELECT #rn:=#rn+1 AS rn1, t1.ID, t1.NAME, t1.WARD_ID
FROM t1
GROUP BY t1.WARD_ID, t1.NAME
ORDER BY t1.WARD_ID, t1.NAME
) s1
INNER JOIN (
SELECT #rn2:=#rn2+1 AS rn2, t2.ID, t2.MONTH1, t2.MONTH2, t2.WARD_ID
FROM t2
GROUP BY t2.WARD_ID, t2.MONTH1,t2.MONTH2
ORDER BY t2.WARD_ID, t2.MONTH1,t2.MONTH2
) s2 ON s1.WARD_ID = s2.WARD_ID
AND s1.rn1 = s2.rn2
But it really doesn't reliably sort the tables to join the same rows every time. I still think there isn't a reliable/repeatable way to join the two tables the same every time.
============================================================
http://sqlfiddle.com/#!9/aa2db0/1 <<<< If ID can be used to reliably sort the two tables, you can use it in the ORDER BYs. I've added it in this Fiddle, and included rows in the setup that would fall before the existing records and potentially change the sorting. This also includes more records in Table 2 than there are in Table 1, so would possibly result in duplicated rows. These new rows are ignored since they can't be matched between tables.
TABLE 1 TABLE 2
id name mob id course mark
1 joe 0000 1 English 77
2 john 0000 2 maths 89
I need to show the name of the person from table 1 who has the MAX(grade) in table 2 using a nested query.
SELECT t1.name
FROM t1
WHERE t1.id = t2.id = (
SELECT id
FROM t2
WHERE mark =
(
SELECT MAX(mark)
FROM t2
)
);
Well, this satisfies the brief ;-):
SELECT a.*
FROM table_a a
JOIN (SELECT * FROM table_b) b
ON b.id = a.id
ORDER
BY mark DESC
LIMIT 1;
I have the next table:
+---------+------------+
| firm_id | service_id |
+---------+------------+
| 6 | 2 |
| 6 | 4 |
| 23 | 7 |
| 23 | 6 |
I want to get ONLY companies who do not have service_id=4 in their service list.
A query of the above table should return only the company with firm_id=23 because firm_id=6 has one record with service_id=4.
I want to make it with one query. Is this possible (without joins)?
Thanks.
P.S. Thanks everyone. User "derobert" suggested very interesting way, what i was looking for.
You can do it several ways. Here is one, with a correlated subquery:
SELECT DISTINCT firm_id FROM table t1
WHERE NOT EXISTS ( SELECT 1 FROM table t2 WHERE t1.firm_id = t2.firm_id AND t2.service_id = 4)
In MySQL-land it is often better to rewrite as a self-join:
SELECT DISTINCT firm_id
FROM table t1 LEFT JOIN table t2 ON (t1.firm_id = t2.firm_id AND t2.service_id = 4)
WHERE t2.firm_id IS NULL
Finally, here is one way to do it that doesn't involve subqueries or joins (but I expect performs worse than either of the above)
SELECT firm_id, CONCAT(',', GROUP_CONCAT(service_id SEPARATOR ','), ',') AS service_ids
FROM table t1
GROUP BY firm_id
HAVING service_ids NOT LIKE '%,4,%'
I confess I haven't actually run these; please forgive typos.
SELECT DISTINCT
firm_id
FROM
TableX AS t
WHERE
NOT EXISTS
( SELECT
*
FROM
TableX AS s
WHERE
s.firm_id = t.firm_id
AND
s.service_id = 4
)
or:
SELECT
firm_id
FROM
TableX
GROUP BY
firm_id
HAVING
COUNT(service_id = 4) = 0
You could try
SELECT * FROM your_table
WHERE firm_id NOT IN
(SELECT DISTINCT firm_id FROM your_table
WHERE service_id = 4) a
As suggested by ypercube (thanks!) you can also try
SELECT DISTINCT firm_id, service_id FROM your_table
WHERE firm_id NOT IN
(SELECT firm_id FROM your_table
WHERE service_id = 4) a