I have a mysql query which I've written in order to grab a group of attributes in the database based on IDs, which relate to a specific group. I'm using OpenCart 2 for my site, and my subquery is as follows:
SELECT GROUP_CONCAT(attribute_id) AS attr_ids
FROM oc79_attribute
WHERE attribute_group_id = 13
Which returns:
44,45,46,47
When I write this within the query which I need to get the attribute names, I only get one result:
SELECT *
FROM oc79_attribute_description
WHERE attribute_id IN(SELECT GROUP_CONCAT(attribute_id) AS attr_ids
FROM oc79_attribute WHERE attribute_group_id = 13)
I only get the result from attribute_id 44, and not the others even though I know the records exist.
Is this the right way to approach this, or am I just missing something?
EDIT:
To clarify, if I write:
SELECT * FROM oc79_attribute_description WHERE attribute_id IN(44,45,46,47)
I get the correct result of 4 records.
Thanks in advance
There is no need for GROUP_CONCAT:
SELECT *
FROM oc79_attribute_description
WHERE attribute_id IN(SELECT attribute_id AS attr_ids
FROM oc79_attribute
WHERE attribute_group_id = 13);
See the difference between:
WHERE attribute_id IN ('44,45,46,47') -- one string
and
WHERE attribute_id IN ('44','45','46','47') -- multiple values
GROUP_CONCAT will return one string with , as separator, what you need is multiple values.
If the attribute table only has one row per attribute_id then you can use a join simple:-
SELECT oc79_attribute_description.*
FROM oc79_attribute_description
INNER JOIN oc79_attribute
ON oc79_attribute_description.attribute_id = oc79_attribute.attribute_id
AND oc79_attribute.attribute_group_id = 13
If it has multiples then you could use DISTINCT:-
SELECT DISTINCT oc79_attribute_description.*
FROM oc79_attribute_description
INNER JOIN oc79_attribute
ON oc79_attribute_description.attribute_id = oc79_attribute.attribute_id
AND oc79_attribute.attribute_group_id = 13
If you really wanted to search through a string of comma separated values (and I really would advise against it) then you could use FIND_IN_SET:-
SELECT *
FROM oc79_attribute_description
WHERE FIND_IN_SET(attribute_id, (SELECT GROUP_CONCAT(attribute_id) AS attr_ids
FROM oc79_attribute WHERE attribute_group_id = 13))
Related
I am trying to make a request where I select from an array of value using the IN, but inside this array, if I have the same value twice, I'd like the request to return the result twice.
To clarify, here is an example:
select id_exo, count(id_exo) FROM BLOC WHERE id_seance IN (10,10) group by id_exo
So inside the IN, I put 2 times the value 10.
Here is the result:
id_exo
count(id_exo)
60
1
82
1
But in count, I'd like to have the number 2 since I have put twice 10 inside my IN.
How can I achieve that?
SELECT id_exo, COUNT(id_exo)
FROM bloc
JOIN (SELECT 10 id_seance
UNION ALL
SELECT 10) val USING (id_seance)
GROUP BY id_exo
Prior to MySQL 8.0 you can join with a sub select:
select * from BLOC as b
inner join (
select 1 as 'id', 10 as 'value'
union
select 2,10
union
select 3,10) as myValues on myValues.value = b.id_seance
You need the id column as the UNION statement removes duplicate rows
If you are lucky enough to have MySQL 8.0 look at the VALUES statement
https://dev.mysql.com/doc/refman/8.0/en/values.html
Here you should instead be able to join with something like
VALUES ROW(10), ROW(10), ROW(10)
In my query I use join table category_attributes. Let's assume we have such rows:
category_id|attribute_id
1|1
1|2
1|3
I want to have the query which suites the two following needs. I have a variable (php) of allowed attribute_id's. If the array is subset of attribute_id then category_id should be selected, if not - no results.
First case:
select * from category_attributes where (1,2,3,4) in category_attributes.attribute_id
should give no results.
Second case
select * from category_attributes where (1,2,3) in category_attributes.attribute_id
should give all three rows (see dummy rows at the beginning).
So I would like to have reverse side of what standard SQL in does.
Solution
Step 1: Group the data by the field you want to check.
Step 2: Left join the list of required values with the records obtained in the previous step.
Step 3: Now we have a list with required values and corresponding values from the table. The second column will be equal to required value if it exist in the table and NULL otherwise.
Count null values in the right column. If it is equal to 0, then it means table contains all the required values. In that case return all records from the table. Otherwise there must be at least one required value is missing in the table. So, return no records.
Sample
Table "Data":
Required values:
10, 20, 50
Query:
SELECT *
FROM Data
WHERE (SELECT Count(*)
FROM (SELECT D.value
FROM (SELECT 10 AS value
UNION
SELECT 20 AS value
UNION
SELECT 50 AS value) T
LEFT JOIN (SELECT value
FROM Data
GROUP BY value) D
ON ( T.value = D.value )) J
WHERE value IS NULL) = 0;
You can use group by and having:
select ca.category_id
from category_attributes ca
where ca.attribute_id in (1, 2, 3, 4)
group by ca.category_id
having count(*) = 4; -- "4" is the size of the list
This assumes that the table has no duplicates (which is typical for attribute mapping tables). If that is a possibility, use:
having count(distinct ca.attribute_id) = 4
You can aggregate attribute_id into array and compare two array from php.
SELECT category_id FROM
(select category_id, group_concat(attribute_id) as attributes from category_attributes
order by attribute_id) t WHERE t.attributes = (1, 2, 3);
But you need to find another way to compare arrays or make sure that array is always sorted.
Is a way to compare 2 records from the same table? I already compared two tables to make sure my records are accurate using
SELECT *
FROM `catalog_category_entity_varchar` c2t
WHERE NOT EXISTS (
SELECT *
FROM `core_url_rewrite` c
WHERE c.category_id = c2t.entity_id
)
Now I am trying to compare the records in catalog_category_entity_varchar for any inconsistancies. Here's an example of my two records.
catalog_category_entity_varchar:
Record 1:
value_id: 68
entity_type_id: 3
attribute_id: 43
store_id: 0
entity_id: 10
value: shop-by
Record 2:
value_id: 73
entity_type_id: 3
attribute_id: 57
store_id: 0
entity_id: 10
value: shop-by.html
entity_id is the unique Identifier. I have to compare the value of url key which is attribute_id = 43 to value of url which is attribute_id 57. I assume I have to use the wildcard % after, which will remove the .html, and another before, which will remove part of the url on any level 2+ category urls (ex. catalog/shirts/shop-by.html).
If it makes it easier I can duplicate the table, and my initial compare statement, I just need to know how to modify the query to match the attribute ID's and use the wildcard.
I'm not sure this will do everything you would like to do, but I think this may be a step in the right direction. It will compare the record with the 43 attribute with the 57 attribute and see if the value field of the 43 record is NOT in the value field of the 57 record.
SELECT *
FROM catalog_category_entity_varchar t1
JOIN catalog_category_entity_varchar t2
ON t1.entity_id = t2.entity_id
AND t2.attribute_id = 57
WHERE t1.attribute_id = 43
AND INSTR(t2.value, t1.value) = 0;
I have a list of ids, and I want to query a mysql table for ids not present in the table.
e.g.
list_of_ids = [1,2,4]
mysql table
id
1
3
5
6
..
Query should return [2,4] because those are the ids not in the table
since we cant view ur code i can only work on asumption
Try this anyway
SELECT id FROM list_of_ids
WHERE id NOT IN (SELECT id
FROM table)
I hope this helps
There is a horrible text-based hack:
SELECT
substr(result,2,length(result)-2) AS notmatched
FROM (
SELECT
#set:=replace(#set,concat(',',id,','),',') AS result
FROM (
select #set:=concat(',',
'1,2,4' -- your list here
,',')
) AS setinit,
tablename --Your tablename here
) AS innerview
ORDER BY LENGTH(result)
LIMIT 1;
If you represent your ids as a derived table, then you can do this directly in SQL:
select list.val
from (select 1 as val union all
select 2 union all
select 4
) list left outer join
t
on t.id = list.val
where t.id is null;
SQL doesn't really have a "list" type, so your question is ambiguous. If you mean a comma separated string, then a text hack might work. If you mean a table, then something like this might work. If you are constructing the SQL statement, I would advise you to go down this route, because it should be more efficient.
Lets say I have a table, myTable, like this:
ID1 Value ID2
1 6.5064 3
2 7.9000 3
3 9.9390 3
4 8.6585 3
What I'm trying to do is SELECT each of those Value's for a given ID2. However, the number of rows returned for Value can change. So, if ID2 = 2, only 1 row might get returned. If drID = 4, 3 rows might get returned.
The part of my query that is trying to handle this is nested, so when I run it I get a "Subquery returns more than 1 row" error. Any idea how I can select a variable number of rows in this way?
Thanks in advance!
Edit: here is what I have so far, and the commented out portion is what I expected to select those values for me, but it throws the above mentioned error:
SELECT drDateTime AS Date,
(SELECT fncName FROM functionlist
WHERE datarecord.fncID = functionlist.fncID) AS FunctionName,
(SELECT alText FROM alarmlevellist
WHERE datarecord.alID = alarmlevellist.alID) AS AlarmDescription
#(SELECT rdValue FROM rawdata
#WHERE datarecord.drID = rawdata.drID)
FROM datarecord
WHERE alID IS NOT NULL AND drSumFlag = 1;
You should show your query.
One common place this problem occurs is in where (or having) clauses. A solution to this problem is to use in rather than =, if the subquery is in the where clause. If you have something like:
where id = (select id2 . . .)
Then change it to:
where id in (select id2 . . .)
Use a join instead of a subquery. I would probably use a join for all tables but that is up to you.
SELECT drDateTime AS Date,
(SELECT fncName FROM functionlist WHERE datarecord.fncID = functionlist.fncID) AS FunctionName,
(SELECT alText FROM alarmlevellist WHERE datarecord.alID = alarmlevellist.alID) AS AlarmDescription,
rawData.drID
FROM datarecord
INNER JOIN rawdata
ON datarecord.drID = rawdata.drID)
WHERE alID IS NOT NULL AND drSumFlag = 1;