Joined results as column names - mysql

I have this Mysql scenario
table1
--------------
id `7` `8`
--------------
1 10 20
2 20 30
table 2
---------------
id code rel
---------------
3 7 1
4 8 2
I am using following statement to get values
SELECT t2.id, t2.code,
CASE t2.code WHEN 7 THEN (SELECT `7` FROM table1 t1 where t1.id = t2.rel)
CASE t2.code WHEN 8 THEN (SELECT `8` FROM table1 t1 where t1.id = t2.rel)
END as val
FROM table2 t2
but it's neither pretty or functional, because I need these values summed, multiplied, etc, and there are a lot of columns.
Is there a way to join these tables and get table1.7 value for t2.rel,t2.code values?
Something similar to
SELECT t2.id, t2.code, eval(t1.(t2.code)) as val
FROM table2 t2
JOIN table1 t1 on t2.rel = t1.id
Thank you very much!

Every column referenced in an SQL query must be fixed at the time you prepare the query. There's no such thing as eval.
However you can use a data value to drive a CASE statement:
SELECT t2.id, t2.code,
CASE t2.code WHEN '7' THEN t1.`7` WHEN '8' THEN t1.`8` END AS `val`
FROM table2 t2
JOIN table1 t1 ON t2.rel = t1.id;
But you'd have to hard-code all the cases before you prepare the query. There's no way for SQL to generate the expressions during execution time as it finds new code values on successive rows of data.

I don't know if it is still relevant.
As you alredy know, there is no such thing as pivot in MySql, but aggregations might look rather easy if the number of columns is defined:
SELECT
SUM(IF(t2.code = 7, `7`, NULL)) as sum7,
AVG(IF(t2.code=8, `8`, NULL)) as avg8
FROM t1 JOIN t2
ON t1.id = t2.rel;

Ok I'm curious if it is possible what your trying to do but this might be a solution for now.
Do a select like this:
SELECT t2.id, t2.code, t1.*
FROM table2 t2
JOIN table1 t1 on t2.rel = t1.id
Resulting in
|| *id* || *code* || *id* || *7* || *8* ||
------------------------------------------
|| 3 || 7 || 1 || 10 || 20 ||
|| 4 || 8 || 2 || 20 || 30 ||
Then in your code concatenate in your result.
If your using php and your result is associative:
echo $result[$result['code']];
I don't think your going to make this happen in a query. You might want to rethink your database design.

Related

SQL select rows with number in sequence

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;

How to equiry data using sql when facing condition?

type cost
A 10
A 11
A 12
B 10
B 10
I have this small sample table. I want to select data where the cost of the same type is different.So the expected outcome should be:
type cost
A 10
A 11
A 12
The cost for A is different so I need to select these "A" out.
So what is the "select" sentence?
Thanks for the replies. Actually my table is little more complex like this
type cost people
A 10 jack
A 11 frank
A 12 lucy
B 10 amy
B 10 tom
I need to select the data meet one of the requirements below:
Same type with different cost
Same type with people "amy"
So the outcome should be like :
type cost people
A 10 jack
A 11 frank
A 12 lucy
B 10 amy
B 10 tom
Select all of type A because the cost is different
Select all of type B because the people has "amy"
I have firgure out how to select for amy like this:
select type, cost, people
from table
where type in
(select type from table where people = 'amy')
I don't know how to combine these conditions.
SQL Fiddle
You can use EXISTS to look for another row with same type but other cost:
select t1.type, t1.cost
from tablename t1
where exists (select * from tablename t2
where t2.type = t1.type
and t2.cost <> t1.cost)
Or have a sub-query that returns type values having different costs, and join with that result:
select t1.type, t1.cost
from tablename t1
join (select type
from tablename
group by type
having max(cost) <> min(cost)) t2
on t1.type = t2.type
Another way is:
select
t.type, t.cost
from t
left join t t1 on t.type = t1.type
and (t.cost <> t1.cost or t1.people = 'amy')
where
not t1.cost is null
group by
t.type, t.cost;
[SQL Fiddle Demo]
Or also:
select *
from t
where exists (
select 1
from t t1
where t1.type = t.type
group by t1.type
having count(distinct t1.cost) > 1
-- below code added your new criteria
union all
select 1
from t t2
where t2.people = 'amy'
);
[SQL Fiddle Demo]

Mysql delete duplicate rows + sort condition

I'm trying to delete some rows from my Mysql table, when one key is duplicate (here "url") and keep a particular one (here the smallest "key1" and "key2")
Example :
Table t1
Id Url Key1 Key2
1 A.com 10 10
2 B.com 20 25
3 B.com 21 25
4 C.com 35 35
5 C.com 35 37
Desired output is :
Table t1
Id Url Key1 Key2
1 A.com 10 10
3 B.com 21 25
5 C.com 35 37
So the query (if it exists) should look like :
Select rows where Url are duplicate
Then sort by Key1 and remove the row where Key1 is strictly inferior
if Key1 are equal, remove the row where Key2 is inferior
Thanks
You want to keep the rows where key1, key2 are maximal. An easy way to express this is:
delete t1 from table t1
where exists (select 1
from t1 t11
where t11.url = t1.url and
(t11.key1 > t1.key1 or
t11.key1 = t1.key1 and t11.key2 > t1.key2
)
);
Alas, MySQL doesn't allow this construct, because you using the table being deleted. So, you can do something like this:
delete t1
from t1 left join
(select t.*,
(select max(key2)
from t1
where t1.url = t.url and t1.key = t.maxkey1
) as maxkey2
from (select url, max(key1) as maxkey1
from t1
group by url
) t
) t
on t1.url = t.url and t1.key1 = t.maxkey1 and t2.key2 = t.maxkey2
where t.url is null;
I think this might be helpful
DELETE t1
FROM t1 as tb1
join t1 as tb2
WHERE tb1.url= tb2.url
and tb1.id < tb2.id
This way you keep the record with the max value on id column
but if you just want to fetch records
SELECT distinct tb1.*
FROM t1 as tb1
join t1 as tb2
WHERE tb1.url= tb2.url
and tb1.id < tb2.id

Fetch duplicate rows with SQL

I am trying to develope a query to fetch the rows having duplicate values, i need to fetch both records i.e duplicating record and the real one, for example
table
id keyword
-------------------
1 Apple
2 Orange
3 Apple
4 Grape
5 Banana
6 Grape
The query result should be:
id keyword
-------------------
1 Apple
3 Apple
4 Grape
6 Grape
Please anyone help me!
Query:
select * from
table where keyword in
(select keyword
from table
group by keyword
having count(keyword)>1)
One way to do it:
SELECT *
FROM `table` t1
WHERE
(SELECT COUNT(*) FROM `table` t2 WHERE t2.keyword = t1.keyword) > 1
And another way:
SELECT t1.*
FROM `table` t1
JOIN `table` t2 ON t1.keyword = t2.keyword
WHERE t1.id != t2.id
This might help:
SELECT t1.id, t1.keyword
FROM table t1
INNER JOIN table t2
ON t1.id != t2.id
AND t1.keyword=t2.keyword
Tested on SQL Fiddle
http://sqlfiddle.com/#!2/44dbb/1/0

MySQL - Help me construct this query

I have a relational DB that I can't think of how to form this query.
Here's the info
Table1
id name
1 Mike
Table2
id table_1_id value setting
1 1 something setting1
2 1 something2 setting2
2 1 something3 setting3
Currently, this is my sql query
SELECT * FROM Table1
JOIN Table2 on Table2.table_1_id = Table1.id
What this outputs is something like this
id name table_1_id value setting
1 Mike 1 something1 setting1
1 Mike 1 something2 setting2
1 Mike 1 something3 setting3
Is it possible to construct this in such a way to return these results so I can export it to a CSV file?
id name table_1_id something1 something2 something3
1 Mike 1 setting1 setting2 setting3
SELECT
Table1.*,
something1Table.setting AS something1,
something2Table.setting AS something2,
something3Table.setting AS something3
FROM Table1
JOIN Table2 AS something1Table ON something1Table.table_1_id = Table1.id AND something1Table.value = 'something'
JOIN Table2 AS something2Table ON something2Table.table_1_id = Table1.id AND something2Table.value = 'something2'
JOIN Table2 AS something3Table ON something3Table.table_1_id = Table1.id AND something3Table.value = 'something3'
You need a conditional aggregation:
select table1.id, table1.name,
max(case when value = 'something1' then setting end) as setting1,
max(case when value = 'something2' then setting end) as setting2,
max(case when value = 'something3' then setting end) as setting3
from table1 join
table2
on table1.id = table2.id
group by table1.id, table1.name
This type of data transformation is known an a pivot but MySQL does not have a pivot function. So you will want to replicate it using an aggregate function with a CASE expression.
If you know the the number of values ahead of time, then you can hard-code your query similar to this:
select t1.id,
t1.name,
max(case when t2.value = 'something' then t2.setting end) as setting1,
max(case when t2.value = 'something2' then t2.setting end) as setting2,
max(case when t2.value = 'something3' then t2.setting end) as setting3
from table1 t1
left join table2 t2
on t1.id = t2.table_1_id
group by t1.id, t1.name;
See SQL Fiddle with Demo
But if you have an unknown number of values that you want to transform into columns, then you can use a prepared statement to generate dynamic sql.
The query would be similar to this:
SET #sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'max(case when t2.value = ''',
value,
''' then t2.setting end) AS `',
value, '`'
)
) INTO #sql
FROM table2;
SET #sql = CONCAT('SELECT t1.id,
t1.name, ', #sql, '
FROM table1 t1
left join table2 t2
on t1.id = t2.table_1_id
group by t1.id, t1.name');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
See SQL Fiddle with Demo
The result of both versions is:
| ID | NAME | SOMETHING | SOMETHING2 | SOMETHING3 |
---------------------------------------------------
| 1 | Mike | setting1 | setting2 | setting3 |
GROUP_CONCAT may be of use. It doesn't give you exactly what you want, because it would put the concatenated values into a single field. But depending on what you're actually trying to accomplish, perhaps you can work around that. The advantage of the GROUP_CONCAT is that it can handle any number of table2 rows per table1 row, whereas the conditional aggregation above hardwires having three entries (which may well be what you want).
SELECT table1.*,
GROUP_CONCAT(value) AS value_group,
GROUP_CONCAT(setting) AS setting_group
FROM table1
INNER JOIN table2
ON table2.table_1_id = table1.id
returns
id,person,value_group,setting_group
1,Mike,"something1,something2,something3","setting1,setting2,setting3"