Database: mysql > ver 5.0
table 1: type_id (int), type
table 2: name_id, name, is_same_as = table2.name_id or NULL
table 3: id, table2.name_id, table1.type_id, value (float)
I want to sum values, and count values in table 3 where table2.name_id are same and also include the values of id where is_same_is=name_id. I want to select all data in table3 for all values in table2.
Apologize if my question is not very clear, and if it has already been answered but I am unable to find a relevant answer. Or dont exactly know what to look for.
[data]. table1
id | type
=========
1 | test1
2 | test2
[data].table2
name_id | name | is_same_as
==============================
1 | tb_1 | NULL
2 | tb_2 | 1
3 | tb_3 | NULL
4 | tb_4 | 1
[data].table3
id | name_id | type_id | value
======================================
1 | 1 | 1 | 1.5
2 | 2 | 1 | 0.5
3 | 2 | 2 | 1.0
output:
name_id| type_id|SUM(value)
=======================================================
1 | 1 |2.0 < because in table2, is_same_as = 1
2 | 2 |1.0
I think the following does what you want:
select coalesce(t2.is_same_as, t2.name_id) as name_id, t3.type_id, sum(value)
from table_3 t3 join
table_2 t2
on t3.name_id = t2.name_id
group by coalesce(t2.is_same_as, t2.name_id), t3.type_id
order by 1, 2
It joins the table on name_id. However, it then uses the is_same_as column, if present, or the name_id if not, for summarizing the data.
This might be what you are looking for: (I haven't tested it in MySQL, so there may be a typo)
with combined_names_tab (name_id, name_id_ref) as
(
select name_id, name_id from table2
union select t2a.name_id, t2b.name_id
from table2 t2a
join table2 t2b
on (t2a.name_id = t2b.is_same_as)
)
select cnt.name_id, t3.type_id, sum(t3.value) sum_val
from combined_names_tab cnt
join table3 t3
on ( cnt.name_id_ref = t3.name_id )
group by cnt.name_id, t3.type_id
having sum(t3.value) / count(t3.value) >= 3
Here's what the query does:
First, it creates 'combined_names_tab' which is a join of all the table2 rows that you want to GROUP BY using the "is_same_as" column to make that determination. I make sure to include the "parent" row by doing a UNION.
Second, once you have those rows above, it's a simply join to table3 with a GROUP BY and a SUM.
Note: table1 was unnecessary (I believe).
Let me know if this works!
john...
Related
I just need to show the values that don't use the specifically ID.
I have two table
table 1
id_xx
1
2
3
4
5
table 2
id | id_xx
3 | 3
4 | 3
4 | 1
I need this results for example. I say which results from ID i need
i need this result where id=3
id_xx
1
2
4
5
or where id=4
id_xx
2
4
5
or where id=1
1
2
3
4
5
You can LEFT JOIN table1 with table2 and apply the filter in the ON clause of the JOIN, and then filter on unmatched records:
SELECT t1.id_xx
FROM table1 t1
LEFT JOIN table2 t2 ON t2.id_xx = t1.id_xx AND t2.id = ?
WHERE t2.id IS NULL
You can replace the question mark with the id that you need to check.
Demo on DB Fiddle:
Given t2.id = 3:
| id_xx |
| ----- |
| 1 |
| 2 |
| 4 |
| 5 |
Given t2.id = 4:
| id_xx |
| ----- |
| 2 |
| 4 |
| 5 |
Another approach is using a Correlated Subquery with NOT EXISTS():
SELECT t1.id_xx
FROM table1 AS t1
WHERE NOT EXISTS (SELECT 1
FROM table2 AS t2
WHERE t2.id = ? -- your input id here
AND t2.id_xx = t1.id_xx)
If you have large table(s), and are worried about performance of these queries, then you may define the following index:
For the correlated subquery, define composite index (id, id_xx) on table2.
ALTER TABLE table2 ADD INDEX(id, id_xx);
Assuming that id_xx is already a Primary Key in the table1. So, you don't need to define any index there. If not, then you can define an index on it.
Considering this table:
+-----+--------+
| id | value |
+-----+--------+
| 1 | 22 |
+-----+--------+
| 2 | 12 |
+-----+--------+
| 3 | 22 |
+-----+--------+
| 4 | 22 |
+-----+ -------+
I can select all where the column value is duplicated like so:
select value from table having count(value) > 1 ;
This will output the Ids 1,3 and 4.
What I'm attempting to do is select where duplicates, but leaving 1 (one) duplicate un selected, so the above would output only the Ids 3 and 4 (or 1 and 3 etc... the duplicate omitted does not matter, only that it is.
How can I achieve this?
This question IS NOT a duplicate of
Using LIMIT within GROUP BY to get N results per group?
You could use an aggregatio function for filter a value for id and the select all the others
select * from table
where (value, id) not in (
select value, max(id)
from table
group by value
having count(value) > 1
)
;
You can do either as:
select *
from test t1
where exists (select 1
from test t2
where t2.value = t1.value
having count(value)>1)
limit 2
OR:
select t1.*
from test t1 inner join
(select value from test t2 having count(value)>1) t2
on t1.value = t2.value
limit 2;
I don't exactly know how to word this question correctly, so I'll start with the data because I think it will make more sense that way.
Starting with these two tables:
Table 1:
user_id | equipment_id
------ | ------
1 | 2
1 | 3
1 | 6
2 | 2
2 | 6
Table 2:
equipment_id | exercise_id
------ | ------
2 | 1
3 | 2
6 | 2
I would like to create this third table:
Table 3:
user_id | exercise_id
------ | ------
1 | 1
1 | 2
2 | 1
It seems like a simple INNER JOIN to get the data, but I'm running into trouble with the second row. I only want that row to show up if user_id 1 has both pieces of equipment listed in Table 2. If either piece of equipment is missing, I don't want the data inserted as shown by user_id 2. I also want to make sure I don't get two instances of user_id 1 for each piece of equipment.
This is the code I have so far:
INSERT INTO Table3 (user_id, exercise_id)
SELECT user_id, exercise_id
FROM Table1
INNER JOIN Table2
ON Table2.equipment_id = Table1.equipment_id
The result I get is this with the rows that need to be removed indicated:
Table 3:
user_id | exercise_id
------ | ------
1 | 1
1 | 2
1 | 2 <--- duplicate of row above
2 | 1
2 | 2 <--- user 2 doesn't have equipment 3, so shouldn't be included
Any help on limiting the results would be greatly appreciated. Thank you!
If I understand correctly, you want to retrieve all the exercises for a user where all the equipment required for that exercise is "available" to the user. I've put some code over at rextester.com/AYRE74108. The important part of that looks like this:
select distinct
t1.user_id,
t2.exercise_id
from
table_1 t1
JOIN table_2 t2 ON
t1.equipment_id = t2.equipment_id
where
not exists
(select 1
from
table_2 t2b
where
t2b.exercise_id = t2.exercise_id
AND not exists (select 1
from
table_1 t1b
where
t2b.equipment_id = t1b.equipment_id
AND t1.user_id = t1b.user_id)
)
To explain the logic: I begin with the standard join and distinct. But then I require that there NOT EXIST any piece of equipment required for the exercise such that that user/equipment combination does NOT EXIST. This is equivalent to saying the user has to have "available" (listed in table 1) all the equipment required for the exercise.
Or schematically: "ALL X are Y" === "NO X is such that Not Y".
I feel that the last row of your output should not be 2 | 2 but 1 | 2.
Also using distinct will ensure that there will be no duplicate rows.
SELECT DISTINCT user_id, exercise_id
FROM Table1
INNER JOIN Table2
ON Table2.equipment_id = Table1.equipment_id
Edit - The mistake in the question threw me off. This should work.
SELECT user_id, table2.exercise_id , sum(table2.equipment_id), sum(b.equipment_id)
FROM Table1
INNER JOIN Table2
ON Table2.equipment_id = Table1.equipment_id
inner join table2 as b
on table2.exercise_id = b.exercise_id
group by user_id, table2.exercise_id
having sum(table2.equipment_id)= sum(b.equipment_id)
I have the below table and now I need to delete the rows which are having duplicate "refIDs" but have atleast one row with that ref, i.e i need to remove row 4 and 5. please help me on this
+----+-------+--------+--+
| ID | refID | data | |
+----+-------+--------+--+
| 1 | 1023 | aaaaaa | |
| 2 | 1024 | bbbbbb | |
| 3 | 1025 | cccccc | |
| 4 | 1023 | ffffff | |
| 5 | 1023 | gggggg | |
| 6 | 1022 | rrrrrr | |
+----+-------+--------+--+
This is similar to Gordon Linoff's query, but without the subquery:
DELETE t1 FROM table t1
JOIN table t2
ON t2.refID = t1.refID
AND t2.ID < t1.ID
This uses an inner join to only delete rows where there is another row with the same refID but lower ID.
The benefit of avoiding a subquery is being able to utilize an index for the search. This query should perform well with a multi-column index on refID + ID.
I would do:
delete from t where
ID not in (select min(ID) from table t group by refID having count(*) > 1)
and refID in (select refID from table t group by refID having count(*) > 1)
criteria is refId is among the duplicates and ID is different from the min(id) from the duplicates. It would work better if refId is indexed
otherwise and provided you can issue multiple times the following query until it does not delete anything
delete from t
where
ID in (select max(ID) from table t group by refID having count(*) > 1)
Some another variant, in some cases a bit faster than Marcus and NJ73 answers:
DELETE ourTable
FROM ourTable JOIN
(SELECT ID,targetField
FROM ourTable
GROUP BY targetField HAVING COUNT(*) > 1) t2
ON ourTable.targetField = t2.targetField AND ourTable.ID != t2.ID;
Hope that will help someone. On big tables Marcus answer stalls.
In MySQL, you can do this with a join in delete:
delete t
from table t left join
(select min(id) as id
from table t
group by refId
) tokeep
on t.id = tokeep.id
where tokeep.id is null;
For each RefId, the subquery calculates the minimum of the id column (presumed to be unique over the whole table). It uses a left join for the match, so anything that doesn't match has a NULL value for tokeep.id. These are the ones that are deleted.
I have a table as so...
----------------------------------------
| id | name | group | number |
----------------------------------------
| 1 | joey | 1 | 2 |
| 2 | keidy | 1 | 3 |
| 3 | james | 2 | 2 |
| 4 | steven | 2 | 5 |
| 5 | jason | 3 | 2 |
| 6 | shane | 3 | 3 |
----------------------------------------
I'm running a select like so:
SELECT * FROM table WHERE number IN (2,3);
The problem im trying to solve is that I want to only grab get results from groups that have 1 or more rows of each number. For instance the above query is returning id's 1-2-3-5-6, when I'd like the results to exclude id 3 since the group of '2' can only return 1 result for the number of '2' and not for BOTH 2 and 3, since there's no row with the number 3 for the group 2 i'd like it to not even select id 3 at all.
Any help would be great.
Try it this way
SELECT *
FROM table1 t
WHERE number IN(2, 3)
AND EXISTS
(
SELECT *
FROM table1
WHERE number IN(2, 3)
AND `group` = t.`group`
GROUP BY `group`
HAVING MAX(number = 2) > 0
AND MAX(number = 3) > 0
)
or
SELECT *
FROM table1 t JOIN
(
SELECT `group`
FROM table1
WHERE number IN(2, 3)
GROUP BY `group`
HAVING MAX(number = 2) > 0
AND MAX(number = 3) > 0
) q
ON t.`group` = q.`group`;
or
SELECT *
FROM table1
WHERE `group` IN
(
SELECT `group`
FROM table1
WHERE number IN(2, 3)
GROUP BY `group`
HAVING MAX(number = 2) > 0
AND MAX(number = 3) > 0
);
Sample output (for both queries):
| ID | NAME | GROUP | NUMBER |
|----|-------|-------|--------|
| 1 | joey | 1 | 2 |
| 2 | keidy | 1 | 3 |
| 5 | jason | 3 | 2 |
| 6 | shane | 3 | 3 |
Here is SQLFiddle demo
On this, you can approach from a fun way with multiple joins for what you WANT qualified, OR, apply a prequery to get all qualified groups as others have suggested, but readability is a bit off for me..
Anyhow, here's an approach going through the table once, but with joins
select DISTINCT
T.id,
T.Name,
T.Group,
T.Number
from
YourTable T
Join YourTable T2
on T.Group = T2.Group AND T2.Group = 2
Join YourTable T3
on T.Group = T3.Group AND T3.Group = 3
where
T.Number IN ( 2, 3 )
So on the first record, it is pointing to by it's own group to the T2 group AND the T2 group is specifically a 2... Then again, but testing the group for the T3 instance and T3's group is a 3.
If it cant complete the join to either of the T2 or T3 instances, the record is done for consideration, and since indexes work great for joins like this, make sure you have one index for your NUMBER criteria, and another index on the (GROUP, NUMBER) for those comparisons and the next query sample...
If doing by more than this simple 2, but larger group, prequery qualified groups, then join to that
select
YT2.*
from
( select YT1.group
from YourTable YT1
where YT1.Number in (2, 3)
group by YT1.group
having count( DISTINCT YT1.group ) = 2 ) PreQualified
JOIN YourTable YT2
on PreQualified.group = YT2.group
AND YT2.Number in (2,3)
Maybe this,if I understand you
SELECT id FROM table WHERE `group` IN
(SELECT `group` FROM table WHERE number IN (2,3)
GROUP BY `group`
HAVING COUNT(DISTINCT number)=2)
SQL Fiddle
This will return all ids where BOTH numbers exist in a group.Remove DISTINCT if you want ids for groups where just one numbers is in.