Reputation: 3
I'm new here, thanks for having me :)
Was hoping to get ideas for a solution to the following: I have a database for scientific specimens and experiments. Each specimen was tested at a certain combination of parameters. Parameters are varied in discrete steps (for example parameter 1: 2, 4 or 6 volts; parameter 3: 2, 10 or 20 amps). A group of specimens make up one experiment.
CREATE TABLE specimens (
id INTEGER PRIMARY KEY,
parameter1 INTEGER not null,
parameter2 INTEGER not null,
parameter3 INTEGER not null,
experiment_id INTEGER not null
);
CREATE TABLE experiments (
id INTEGER PRIMARY KEY
);
INSERT INTO `experiments` (`id`) VALUES
(1),
(2),
(3);
INSERT INTO `specimens` (`id`, `parameter1`, `parameter2`, `parameter3`, `experiment_id`) VALUES
(1, 2, 2, 2, 1),
(2, 2, 2, 10, 1),
(3, 2, 2, 20, 1),
(4, 2, 2, 2, 2),
(5, 4, 2, 2, 2),
(6, 6, 2, 2, 2),
(7, 2, 2, 2, 3),
(8, 4, 2, 10, 3),
(9, 6, 2, 20, 3);
I'm trying to put together a query that does the following:
Select all specimens from the database, for which there exists at least one other specimen within the same experiment, that was tested at a different level of a certain factor.
For example:
I'm (obviously) not a pro at this, but so far I figured it can't be done with JOIN, as I need to vertically append rows to my set of results, but it can't be a UNION query either, because the second query can't interact with the first one. My current progress is something like:
SELECT specimens1.*
FROM specimens AS specimens1
WHERE
specimens1.id = 2
OR specimens1.id IN (
SELECT specimens2.id
FROM specimens AS specimens2
WHERE specimens2.experiment_id = specimens1.experiment_id
)
Which turned out to be nonsense. I hoped it would at least get me specimens 1, 2 and 3 for a start, as they belong to the same experiment. It doesn't, though. Also, I have no idea how to implement the "at least one other level of a certain factor within the same experiment" condition.
Does anyone have a hint? Thank you for your time!
Cheers, Max
Upvotes: 0
Views: 42
Reputation: 3
Thanks a lot, P.Salmon! From your answer I was able to construct the following, which gets the result I actually had in mind:
SELECT * FROM specimens
HAVING FIND_IN_SET(id, (SELECT group_concat(gc)
FROM
(SELECT 'parameter1' parameter)
a LEFT JOIN
(
SELECT e.id,'parameter1' AS parameter, GROUP_CONCAT(s.id) gc
FROM experiments e
JOIN specimens s ON s.experiment_id = e.id
GROUP BY e.id
HAVING COUNT(DISTINCT parameter1) > 1
)
b ON b.parameter = a.parameter
)) > 0
I was looking for the actual data rows of all specimens meeting one distinct-parameter-criterion at a time, rather than a full set of all possible results. Example above is for parameter1 only, then.
Upvotes: 0
Reputation: 17640
A union does help as does group concat and left joining all parameters.
DROP TABLE IF EXISTS SPECIMENS,EXPERIMENTS;
CREATE TABLE specimens (
id INTEGER PRIMARY KEY,
parameter1 INTEGER not null,
parameter2 INTEGER not null,
parameter3 INTEGER not null,
experiment_id INTEGER not null
);
CREATE TABLE experiments (
id INTEGER PRIMARY KEY
);
INSERT INTO `experiments` (`id`) VALUES
(1),
(2),
(3);
INSERT INTO `specimens` (`id`, `parameter1`, `parameter2`, `parameter3`, `experiment_id`) VALUES
(1, 2, 2, 2, 1),
(2, 2, 2, 10, 1),
(3, 2, 2, 20, 1),
(4, 2, 2, 2, 2),
(5, 4, 2, 2, 2),
(6, 6, 2, 2, 2),
(7, 2, 2, 2, 3),
(8, 4, 2, 10, 3),
(9, 6, 2, 20, 3);
select a.parameter, group_concat(gc) vals from
(
(select 'parameter1' parameter union select 'parameter2' union all select 'parameter3') a
left join
(
select e.id,'parameter1' as parameter,group_concat(s.id) gc
from experiments e
join specimens s on s.experiment_id = e.id
group by e.id having count(distinct parameter1) > 1
union all
select e.id,'parameter2' as parameter,group_concat(s.id) gc
from experiments e
join specimens s on s.experiment_id = e.id
group by e.id having count(distinct parameter2) > 1
union all
select e.id,'parameter3' as parameter,group_concat(s.id) gc
from experiments e
join specimens s on s.experiment_id = e.id
group by e.id having count(distinct parameter3) > 1
) b on b.parameter = a.parameter
)
group by a.parameter;
+------------+-------------+
| parameter | vals |
+------------+-------------+
| parameter1 | 4,5,6,7,8,9 |
| parameter2 | NULL |
| parameter3 | 1,2,3,7,8,9 |
+------------+-------------+
3 rows in set (0.102 sec)
Upvotes: 1