SQL select rows with number in sequence - mysql

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;

Related

SQL query to join two tables with no repeated values?

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.

How to select random rows where the sum of a column equals to X - MySQL

How i can select random rows of a table when the sum of a column equals to a value ? (MySQL)
Value : 3
Name Price
------------------------
A 1
B 2
C 1
D 3
E 2
I wan to get all possibilities (A + B, D, E + C...).
I have tried to do this :
SELECT * FROM table HAVING SUM(column) = 3 ORDER BY RAND();
Thank's
Thibeault
You need to join the table with itself to get pairs of rows.
SELECT t1.name as name1, t1.price as price1, t2.name AS name2, t2.price AS price2
FROM yourTable AS t1
JOIN yourTable AS t2 ON t1.price + t2.price = 3
ORDER BY RAND()
LIMIT 1

Join query with limit results

ID Name
1 A
2 B
3 C
4 D
5 E
6 F
7 G
8 H
9 I
10 J
And other table is
ID Image Date
1 aa.jpg 5/17/2016
1 bb.jpg 5/20/2016
1 aa1.jpg 5/15/2016
2 1.jpg 5/17/2016
3 2.jpg 5/17/2016
3 3.jpg 5/20/2016
4 x.jpg 5/17/2016
8 tt.jpg 5/17/2016
9 ww.jpg 5/21/2016
10 21.jpg 5/17/2016
5 67.jpg 5/17/2016
6 3d.jpg 5/17/2016
7 w3.jpg 4/17/2016
7 y78.jpg 5/17/2016
I have written below query to get this result.
select t1.id,t1.name,t2.image,t2.date
from emp t1
join images t2 ON t1.id = t2.id
result:
ID Name Images Date
2 B 1.jpg 5/17/2016
1 A bb.jpg 5/20/2016
1 A aa1.jpg 5/15/2016
1 A aa.jpg 5/17/2016
.
.
.
Here is my actual problem:
I have to add limit functionality like limit 0,100. in my limit 0,3
So my expectation is if any id coming with query so all id should be come.
I guess your requirement is to choose a set of ID values that yields approximately 100 rows in your result set.
LIMIT makes very little sense without ORDER BY; you're just choosing an unpredictable subset of the result set. So, I will guess you want to ORDER BY ID.
First, you need to figure out which ID values are in your set. That's relatively simple. (I'm using LIMIT 0,5).
SELECT DISTINCT id
FROM (
select t1.id
from emp t1
join images t2 ON t1.id = t2.id
order by t1.id
limit 0,5
) a
Then, use that as a subquery to limit your query. Here's a SqlFiddle demonstrating this (http://sqlfiddle.com/#!9/44430d/4/0).
select t1.id
from emp t1
join images t2 ON t1.id = t2.id
where t1.id IN (
SELECT DISTINCT id
FROM (
select t1.id
from emp t1
join images t2 ON t1.id = t2.id
order by t1.id
limit 0,5
) a
)
order by t1.id
This query is likely to yield more rows than your LIMIT, of course: it augments its result set with extra images as necessary. The SqlFiddle example yields six rows rather than five (http://sqlfiddle.com/#!9/44430d/4/0)

SQL show the same column multiple times

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.

Mysql derived table

Suppose i have a mysql table name table with fields
rank
date
id
The values are like:
10, 2012-01-01, 3
9, 2012-01-04, 3
5, 2012-01-07, 3
3, 2012-01-10, 3
10, 2012-01-01, 4
6, 2012-01-04, 4
7, 2012-01-07, 4
In a single sql, how can i get both last and first values sorted by date grouped by id?
I know how to get first one or last one
SELECT rank, id FROM
(SELECT rank, id FROM table ORDER BY date DESC) s GROUP BY id;
I would like that the fields returned to be somethink like: lastrank, firstrank and id.
Thank you
Try this:
select id,
max(if(MyOrder = 1, rank, null)) as FirstRank,
max(if(MyOrder = 2, rank, null)) as LastRank
from (
select t1.id, t1.rank, 1 MyOrder from t t1
left join t t2 on
t1.id = t2.id and t1.date > t2.date
where t2.date is null
union
select t1.id, t1.rank, 2 from t t1
left join t t2 on
t1.id = t2.id and t1.date < t2.date
where t2.date is null
) s
group by id
The result of this query taking your sampla data as input is:
+----+-----------+----------+
| ID | FIRSTRANK | LASTRANK |
+----+-----------+----------+
| 3 | 10 | 3 |
| 4 | 10 | 7 |
+----+-----------+----------+
I'm not fully sure that I understand your question, but I'm going to try to answer anyway.
SELECT min(rank), max(rank), id
FROM table
ORDER BY date DESC
GROUP BY id;
When grouping, you can use aggregate functions on the results to get specific samples from the groups.
Try this query -
SELECT
t1.*,
IF(t1.date = t2.min_date, 'FIRSTRANK', 'LASTRANK') rank_type
FROM table_rank t1
JOIN (
SELECT id, MAX(date) max_date, MIN(date) min_date FROM table_rank GROUP BY id
) t2
ON t1.id = t2.id AND (t1.date = t2.min_date OR t1.date = t2.max_date)
Involve GROUP_CONCAT(rank ORDER BY date), and use SUBSTRING_INDEX.