MySQL single table, select value based on multiple rows - mysql

From the table below, how would I select all animalIds that have a specific combination of attributeIds e.g. if I supplied attributeIds 455 & 685 I'd expect to get back animalIds 55 & 93
Table name: animalAttributes
id attributeId animalId
1 455 55
2 233 55
3 685 55
4 999 89
5 455 89
6 333 93
7 685 93
8 455 93
I have the following query that seems to work, however, I'm not sure if there is a more robust way?
SELECT animalId
FROM animalAttributes
WHERE attributeId IN (455,685)
GROUP BY animalId
HAVING COUNT(DISTINCT attributeId) = 2;

If you really want accurate results, you could go with a fool-proof method like this:
select distinct base.animalId
from animalAttributes base
join animalAttributes a on base.animalId = a.animalId
and a.attributeId = 455
where base.attributeId = 685
If you later needed 3 matching attributes, you could just add another join:
select distinct base.animalId
from animalAttributes base
join animalAttributes a on base.animalId = a.animalId
and a.attributeId = 455
join animalAttributes b on base.animalId = b.animalId
and b.attributeId = 999
where base.attributeId = 685

SELECT DISTINCT `animalId` FROM `animalAttributes` WHERE `attributeId` = 455
INTERSECT
SELECT DISTINCT `animalId` FROM `animalAttributes` WHERE `attributeId` = 685

SELECT DISTINCT animalId
FROM animalAttributes
WHERE attributeId IN (455,685)
or
SELECT animalId
FROM animalAttributes
WHERE attributeId IN (455,685)
GROUP BY animalId

Related

Join two tables using mysql

table:tab1
id date_time zoneid accountid slotid trequest bidder width height
_50832 2017-09-04 15:41:06 153 1654 153x468x60 10 aaa 468 60
_50832 2017-09-04 15:41:06 152 1654 152x468x60 10 bbb 468 60
table:tab2
id date_time zoneid accountid slotid bidder count
_50832 2017-09-04 15:41:06 152 1654 152x468x60 bbb 6
_50832 2017-09-04 15:41:06 152 1654 152x468x60 bbb 4
_50832 2017-09-04 15:41:06 153 1654 153x468x60 aaa 9
_50832 2017-09-04 15:41:06 153 1654 153x468x60 aaa 1
below is my query:
SELECT SUM(req.trequest) as REQ, SUM(win.count) as IMP
FROM tab1 as req
JOIN tab2 as win ON (req.id=win.id AND req.zoneid=win.zoneid)
GROUP BY req.zoneid
I get below result,
REQ IMP
20 10
20 10
IMP count is correct but I get wrong REQ count. My expected result is
REQ IMP
10 10
10 10
How to get my expected result?
Lets find the sum of trequest and count separately based on zoneid and id.Then use these two results ( t1 and t2 ) in the inner join.
Count mismatch problem shown in the question occur due to multiple rows satisfying the joining conditions.
In this solution we will only have one entry for each zoneid in both the results ( t1 and t2 ). So the problem is avoided.
Note: You can remove the id column from the GROUP BY clause if it doesn't make any difference.
SELECT t1.id, t1.zoneid, t1.REQ, t2.IMP FROM
(SELECT id,zoneid,SUM(trequest) as REQ
FROM tab1 GROUP BY zoneid,id ) t1
INNER JOIN
(SELECT id,zoneid SUM(win.count) as IMP
FROM tab2 GROUP BY zoneid,id ) t2
ON t1.id = t2.id
AND t1.zoneid = t2.zoneid
Let's try first sumwin.count and group records in sub-query, after it join tables. Try in following:
SELECT SUM(req.trequest) as REQ, SUM(win.count) as IMP
FROM tab1 as req
JOIN (
SELECT SUM(win.count) as IMP, win.zoneid, win.id
FROM tab2 as win
GROUP BY win.zoneid, win.id) AS win ON req.id=win.id AND req.zoneid=win.zoneid
GROUP BY req.zoneid
Instead of req.zoneid. You should try win.zoneid. What seems is that the rows in table 1 are counted multiple times as zoneid in table 2 comes twice. So win.zoneid would group it and avoid the repetition.
Updated: The solution posted by #mayur panchal is the correct one as you don't need to SUM the rows in first table as they belong to different zoneid. If you SUM them you will obviously get the 20 repeated twice.

combine two columns in 1 column mysql

i have tablea and table b
tablea :
Nama Jumlah
A 66
B 95
C 47
E 57
F 52
tableb:
Nama Jumlah Gaji
A 35 47
B 28 51
C 18 24
D 27 30
E 30 29
G 31 16
how to make query that can combine two tables in one table an to be like this
result :
Nama Jumlah Gaji
A 101 47
B 123 51
C 65 24
D 27 30
E 87 29
F 52 0
G 31 16
it's my query. but i can't get the the result like that.
SELECT a.nama, (a.jumlahtotala+b.jumlahtotalb) AS Jumlah FROM (SELECT nama, SUM(jumlah) AS jumlahtotala FROM tablea GROUP BY nama) a JOIN (SELECT nama, SUM(jumlah) AS jumlahtotalb, SUM(gaji) AS gaji FROM tableb GROUP BY nama) b GROUP BY a.name
thanks for your help
EDITED
Sorry for another question in comment
Try joining the two tables like:
SELECT b.Nama, IFNULL(a.Jumlah, 0) + b.Jumlah, b.Gaji
FROM tablea a RIGHT JOIN tableb b
ON a.Nama = b.Nama
If Nama is not unique in tablea or tableb, or if rows exist in tablea that don't have a matching row in tableb, for example:
tablea:
Nama Jumlah
A 66
B 95
C 47
C 18
tableb:
Nama Jumlah Gaji
A 35 47
C 0 24
D 27 30
Z NULL 99
If an acceptable result is to return a single occurrence of each value of Nama along with the totals of Jumlah and Gaji, then one approach (assuming the datatypes of the Nama and Jumlah columns is compatible), and assuming that there isn't a requirement to return the rows in a particular sequence, one option is to combine the two sets with a UNION ALL operator into a derived table, and then use SUM() aggregate.
For example:
SELECT t.Nama
, SUM(t.Jumlah) AS Jumlah
, SUM(t.Gaji) AS Gaji
FROM ( SELECT b.Nama
, b.Jumlah
, b.Gaji
FROM tableb b
UNION ALL
SELECT a.Nama
, a.Jumlah
, NULL
FROM tablea a
) t
GROUP BY t.Nama
Because of the derived table (i.e. the way that MySQL processes derived tables), this will likely not be the most efficient approach for large sets.

MySQL Query suggestion with access id

I have a MySQL table like this
ownerlisting_access_id property_id mainaccess_id subaccess_id access_value
62 2 35 41 Yes
64 2 35 36 Yes
123 4 35 41 Yes
125 4 35 36 Yes
306 7 35 41 Yes
307 7 35 42 Yes
308 7 35 36 Yes
I want a query that will give me this output using subaccess_id(41,42,36) and mainaccess_id(35) -
ownerlisting_access_id property_id mainaccess_id subaccess_id access_value
306 7 35 41 Yes
307 7 35 42 Yes
308 7 35 36 Yes
I need to get the property_id as 7 using sub access id with 41, 42, 36
The fastest way to get an answer to your question is to describe the PROBLEM not just show results you need. It's not clear what is the logic behind your desired output. I guess you need the rows with the highest property_id for each group subaccess_id. If so here is the query:
select * from t
join (select subaccess_id, max(property_id) MAX_property_id
from t
where mainaccess_id=35
and
subaccess_id in (41,42,36)
group by subaccess_id
) t1
on t.subaccess_id=t1.subaccess_id
and
t.property_id=t1.MAX_property_id
SQLFiddle demo
Also here is a query that outputs results you needed :) But I guess it doesn't solve your PROBLEM:
select * from t where property_id=7
Try this:
SELECT table1.* FROM (
select property_id, group_concat(DISTINCT subaccess_id ORDER BY subaccess_id) as list
from table1 as t1 group by property_id
) a, table1
WHERE a.property_id = table1.property_id
AND a.list = '36,41,42'
Working query: http://sqlfiddle.com/#!2/4744ea/2
SELECT MAX(DISTINCT property_ID) AS property_ID, mainaccess_id,
MAX(DISTINCT subaccess_id) AS subaccess_id, MAX(DISTINCT access_value)
FROM tableName GROUP BY mainaccess_id ORDER BY mainaccess_id
SELECT property_ID, mainaccess_id, subaccess_id, access_value
FROM tableName t1
WHERE t1.mainaccess_id = 35
AND (t1.subaccess_id = 41 OR t1.subaccess_id = 42 OR t1.subaccess_id = 36)
AND t1.property_ID = (SELECT MAX(t2.property_ID)
FROM tableName t2
WHERE t2.mainaccess_id = 35
AND (t2.subaccess_id = 41 OR t2.subaccess_id = 42 OR t2.subaccess_id = 36))

MySQL, How do I only select rows based on other rows data?

Ok, here's the deal, I have a table for stats where there are different types and I only want to select a row if it has a previous (not directly previous) row that has some matching data (hash) and is unique based on another column value.
In the following example we need to only get SALE rows
This example should help:
id link_id member_id stat_type hash
----------------------------------------------
108 41 82 SALE fffff
107 41 82 CLICK fffff
106 41 82 CLICK eeeee
105 41 67 SALE ddddd
104 41 67 CLICK ddddd
103 41 35 SALE ccccc
102 41 35 CLICK bbbbb
101 41 35 CLICK aaaaa
The only row I want to get back here is member_id = 67 because that member's only previous CLICK to link_id 41 has the same hash. Members 82 and 35 do not get selected because they both have a previous click to link_id 41 with a mismatched hash.
Query result should be:
id link_id member_id stat_type hash
----------------------------------------------
105 41 67 SALE ddddd
TIA
If I've understood your problem correctly, then you first need to group the table by link_id and member_id, filter those groups for ones that contain only one distinct hash, and then join the results back to your table to obtain all the matching SALE records:
SELECT * FROM my_table NATURAL JOIN (
SELECT link_id, member_id
FROM my_table
GROUP BY link_id, member_id
HAVING COUNT(DISTINCT hash) = 1
) t WHERE stat_type = 'SALE'
See it on sqlfiddle.
One way to get this result is to use an anti-join pattern.
SELECT r.*
FROM mytable r
LEFT
JOIN ( SELECT t.member_id
, t.link_id
, t.hash
FROM mytable t
GROUP
BY t.member_id
, t.link_id
, t.hash
) s
ON s.member_id = r.member_id
AND s.link_id = r.link_id
AND NOT (s.hash = r.hash)
WHERE r.stat_type = 'SALE'
AND s.member_id IS NULL
The inline view (derived table) aliased as s gets all of the distinct hash values for each member_id and link_id. That is left joined to all of the rows in the table that have stat_type='SALE', with matching member_id and link_id, and with a NON-matching hash.
The "trick" is the s.member_id IS NULL predicate. Any rows that found a match (i.e. a non-matching HASH will have a non-null value for s.member_id. Only rows that did not have a match will return a NULL (due to the LEFT JOIN).

How to select distinct rows where 2 columns should match on multiple rows?

I have a table like this :
id | user_id | param_id | param_value
1 1 44 google
2 1 45 adTest
3 1 46 Campaign
4 1 47 null
5 1 48 null
6 2 44 google
7 2 45 adAnotherTest
8 2 46 Campaign2
9 2 47 null
10 2 48 null
I want to fetch all the user_ids where (param_id = 44 AND param_value=google) AND (param_id= 45 AND param_value = adTest) . So the above where clause should give only user_id = 1 and not user_id = 2 . They both have google at param_id 44 but only user 1 has param_value adTest at param_id = 45 .
The problem is the n the future more params could be added . I need to find a dynamic query . Here what i have tryed :
SELECT DISTINCT up.user_id FROM user_params AS up
LEFT JOIN user_params AS upp ON up.id = upp.id
WHERE up.param_id IN (?,?)
AND upp.param_value IN (?,?)
SELECT DISTINCT up.user_id
FROM user_params AS up
LEFT JOIN user_params AS upp ON up.id = upp.id
group by up.user_id
having sum(param_id = 44 AND param_value = 'google') >= 1
and sum(param_id = 45 AND param_value = 'adTest') >= 1
Another way:
SELECT -- DISTINCT
up1.user_id
FROM
user_params AS up1
JOIN
user_params AS up2
ON up1.user_id = up2.user_id
WHERE
up1.param_id = 44 AND up1.param_value = 'google'
AND
up2.param_id = 45 AND up2.param_value = 'adTest' ;
You do not need the DISTINCT, if there is a UNIQUE constraint on (user_id, param_id)
For efficiency, add an index on (param_id, param_value, user_id)
The problem you are dealing with is called "Relational Division" and there is a great answer by #Erwin Brandstetter here: How to filter SQL results in a has-many-through relation, with a lot of ways to write such a query, along with performance tests.
The tests were done in Postgres so some of the queries do not even run in MySQL but at least half of them do run and efficiency would be similar in many of them.
If you want to optimize this should give the same results without the need an LEFT JOIN table scans (thanks to juergen d for having part)
SELECT
user_id
FROM
user_params
WHERE
param_id IN(44, 45)
AND
param_value IN('google', 'adTest')
GROUP BY
user_id
HAVING
sum(param_id = 44 AND param_value = 'google') >= 1
AND
sum(param_id = 45 AND param_value = 'adTest') >= 1
;
see http://sqlfiddle.com/#!2/17b65/4 for demo