how to get records in the following scenario - mysql

I have a table like below :
node_name id term_name
----------------------------------------------
test1 001 physics
test1 001 maths
test1 001 chemistry
test2 002 physics
test2 002 maths
Given a combination of term names I want to find all rows where the id set only contains exactly the given term names.
For example given the term names physics & maths my output should be like below
node_name id term_name
----------------------------------------------
test2 002 physics
test2 002 maths
Id set 001 contains also chemistry that is why it should not be included.

Your question: get all rows where no other rows with same id but other term_names exists
SELECT * FROM <table> x WHERE
term_name IN ('physics','maths') AND
NOT EXISTS (SELECT * FROM <table> WHERE id=x.id AND term_name NOT IN ('physics','maths'))

first of all you need to parse your query to convert the '&' to SQL 'OR' operator
in PHP :
//Parse the query
$arr = explode('&',$query);
$where = '';
//get the term count
$count = count($arr);
foreach($arr as $value){
$where .= "term_name = '" . $value . "' OR";
}
//Remove last or
$where = rtrim($where,'OR');
then :
use L
"select node_name ,count(1) as Total from my table where $where
group by node_name
having Total =" . $count
Finally :
your query must be in this format:
select x,count(1) as total from mytable where field1 = 'term1' or field1 = 'term2' having total = 2

One possible way to do this:
select id, node_name
from nodes join
(select id,
count(*)
from nodes
where node_name in ('physics','math')
group by id
having count(*) = 2 // this is set when generating the query ) as eligible_nodes
on nodes.id = eligible_nodes.id

Related

How to query CodeIgniter in two table with condition?

I got headache of this query issue in CodeIgniter
I'm a beginner of this framework
How to query in CodeIgniter of Query result in Table 1 and Table 2.
If you are using the Query Builder in Codeigniter version 3 (I assume since your using the tag codeigniter-3), then you could specify the columns in your select statement and use join to achieve what you want:
$this->db->select('t1.Account, t1.Client, t1.Wala, t2.Meron');
$this->db->from('Table1 t1');
$this->db->join('Table2 t2', 't1.Account = t2.Account AND t1.Client = t2.Client');
$this->db->where('t1.Account', 111); // IF YOU ONLY WANT A SPECIFIC ACCOUNT
$this->db->group_by('t1.Account, t1.Client');
$query = $this->db->get();
if ($query->num_rows() > 0){
$result = $query->result(); // ARRAY OF OBJECTS
foreach ($result as $r){
echo $r->Account."\t";
echo $r->Client."\t";
echo $r->Wala."\t";
echo $r->Meron."\n";
}
}
The result:
| Account | Client | Wala | Meron |
|---------|--------|------|-------|
| 111 | Doe | | 50 |
| 111 | Jhon | 200 | 50 |
Documentation: https://www.codeigniter.com/userguide3/database/query_builder.html
Alternatively, you can use a pure SQL query to get the same result:
$sql = 'SELECT t1.Account, t1.Client, t1.Wala, t2.Meron
FROM Table1 t1
JOIN Table2 t2
ON t1.Account = t2.Account AND t1.Client = t2.Client
WHERE t1.Account = 111
GROUP BY t1.Account, t1.Client';
$query = $this->db->query($sql);
If you are using MySQL > 5.6 then use the group by function any_value():
t1.Account, t1.Client, ANY_VALUE(t1.Wala), ANY_VALUE(t2.Meron)
To be used with caution since unexpected results may appear if you have multiple rows with different values in the columns "Wala" or "Meron" for the same Account and Client.

If the column is empty, select the same column using different where clause

Is there a way to select rpd.name using a different WHERE clause if the previous one returns an empty string?
I've looked into CASE, but I'm not sure how would I go about using it.
table replacement_part
part_id href
1 url_1
2 url_2
3 url_3
table replacement_part_description
part_id language_id name
1 2
1 1 hose
2 2
2 1 control module
3 2 vonkajsi kryt
3 1 outer casing
expected output
part_id href name
1 url_1 hose
2 url_2 control module
3 url_3 vonkajsi kryt
SELECT *
FROM replacement_part AS rp
LEFT JOIN replacement_part_description AS rpd
ON (rp.part_id = rpd.part_id)
WHERE language_id = :id
So something like
if rpd.name = ''
WHERE language_id = a,
else
WHERE language_id = b
This ?
SELECT *
FROM replacement_part AS rp
LEFT JOIN replacement_part_description AS rpd
ON (rp.part_id = rpd.part_id)
WHERE
(
language_id = :id
AND (rpd.name = '' OR rpd.name IS NULL)
)
OR language_id = b
One way is to join the rpd table twice, moving the where clause on the ON condition, and then use COALESCE:
SELECT
...,
COALESCE(rpd1.name, rpd2.name) AS name
FROM
replacement_part rp LEFT JOIN replacement_part_description rpd1
ON rp.part_id = rpd1.part_id AND rpd1.language=a
LEFT JOIN replacement_part_description rpd2
ON rp.part_id = prd2.part_id AND rpd2.language=b
here I suppose that the language is on the description table. If name is an empty string, instead of coalesce you could use CASE WHEN:
CASE WHEN rpd1.name='' OR rpd1.name IS NULL THEN rpd2.name ELSE rpd1.name END AS Name
You can use order by and limit to get one row with priorities:
select . . .
from . . .
where (language_id = a and rpd.name = '') or
language_id = b
order by (language_id = a) desc -- put the "a" rows first
limit 1;

mysql - please advice with correct regexp syntax

I am looking for correct query in mysql db. Let's consider I have tables:
users:
id | user_name | desc
--------------------------
1 | john | tall
2 | john | fat
3 | maria | pretty
items:
id | item_name | color
--------------------------
1 | trousers | red
2 | shoes | blue
3 | shoes | red
My search engine searches database to select result with query:
SELECT i.item_name, i.color, u.user_name, u.desc
FROM users u, items i
WHERE u.id = i.id
AND item_name REGEXP $keywords
AND user_name REGEXP $keywords
Variable $keywords is like this:
$keywords = explode(' ', $_POST['keywords']);
$keywords = implode('|', $keywords);
Now when $keywords = 'john trousers' it works all fine - i get user with id = 1. It's ok. But when I set $keywords = 'john' it returns empty string. I know even why - there is no 'john' in item_name so my AND condition returns false. The question is:
What is correct regexp expression to return user = 1 with $keywords = "john trousers" and if $keyword = 'john' get two lines - with id = 1 and id = 2?
Thanks in advance.
You can reverse the comparison, using the column value as the search value (and use LIKE instead of REGEXP):
SELECT i.item_name, i.color, u.user_name, u.desc
FROM users u, items i
WHERE u.id = i.id
AND $keywords like concat('%', item_name, '%')
AND $keywords like concat('%', user_name, '%')
Note that although this is a neat approach, it only works when keywords contains the whole value for the column. To make a more sophisticated comparison, you'd need to play with splitting up the values etc (you would have to do your own investigation)

Does MySQL table row contain two values

I have a table with two columns:
ID1 | ID2
---------
1 | A
3 | V
1 | C
4 | B
5 | Q
1 | S
And I want to be able to find out if any row has, say ID1 = 5 and ID2 = Q , and return a true / false value.
Yes, Of course
SELECT * FROM table where ID1='5' and ID2='Q'
PHP (I am just guessing this backend)
$query = "SELECT * FROM table where ID1='5' and ID2='Q'";
$result = mysql_query($query);
if(mysql_num_rows($result)) { return true; }
else { return false; }
1 means TRUE for mysql
SELECT 1
FROM your_table
WHERE ID1 = 5 AND ID2 = 'Q'
for example this?
SELECT 1
FROM TABLE
WHERE ID1 = 5 AND ID2 = 'Q'
Efficient query for your purpose (faster than other examples):
SELECT 1 FROM table where ID1='5' and ID2='Q' LIMIT 1
PHP sample:
<?php
$query = "SELECT 1 FROM table where ID1='5' and ID2='Q' LIMIT 1";
echo bool(mysql_num_row(mysql_query($query)));
?>

Split a MYSQL string from GROUP_CONCAT into an ( array, like, expression, list) that IN () can understand

This question follows on from MYSQL join results set wiped results during IN () in where clause?
So, short version of the question. How do you turn the string returned by GROUP_CONCAT into a comma-seperated expression list that IN() will treat as a list of multiple items to loop over?
N.B. The MySQL docs appear to refer to the "( comma, seperated, lists )" used by IN () as 'expression lists', and interestingly the pages on IN() seem to be more or less the only pages in the MySQL docs to ever refer to expression lists. So I'm not sure if functions intended for making arrays or temp tables would be any use here.
Long example-based version of the question: From a 2-table DB like this:
SELECT id, name, GROUP_CONCAT(tag_id) FROM person INNER JOIN tag ON person.id = tag.person_id GROUP BY person.id;
+----+------+----------------------+
| id | name | GROUP_CONCAT(tag_id) |
+----+------+----------------------+
| 1 | Bob | 1,2 |
| 2 | Jill | 2,3 |
+----+------+----------------------+
How can I turn this, which since it uses a string is treated as logical equivalent of ( 1 = X ) AND ( 2 = X )...
SELECT name, GROUP_CONCAT(tag.tag_id) FROM person LEFT JOIN tag ON person.id = tag.person_id
GROUP BY person.id HAVING ( ( 1 IN (GROUP_CONCAT(tag.tag_id) ) ) AND ( 2 IN (GROUP_CONCAT(tag.tag_id) ) ) );
Empty set (0.01 sec)
...into something where the GROUP_CONCAT result is treated as a list, so that for Bob, it would be equivalent to:
SELECT name, GROUP_CONCAT(tag.tag_id) FROM person INNER JOIN tag ON person.id = tag.person_id AND person.id = 1
GROUP BY person.id HAVING ( ( 1 IN (1,2) ) AND ( 2 IN (1,2) ) );
+------+--------------------------+
| name | GROUP_CONCAT(tag.tag_id) |
+------+--------------------------+
| Bob | 1,2 |
+------+--------------------------+
1 row in set (0.00 sec)
...and for Jill, it would be equivalent to:
SELECT name, GROUP_CONCAT(tag.tag_id) FROM person INNER JOIN tag ON person.id = tag.person_id AND person.id = 2
GROUP BY person.id HAVING ( ( 1 IN (2,3) ) AND ( 2 IN (2,3) ) );
Empty set (0.00 sec)
...so the overall result would be an exclusive search clause requiring all listed tags that doesn't use HAVING COUNT(DISTINCT ... ) ?
(note: This logic works without the AND, applying to the first character of the string. e.g.
SELECT name, GROUP_CONCAT(tag.tag_id) FROM person LEFT JOIN tag ON person.id = tag.person_id
GROUP BY person.id HAVING ( ( 2 IN (GROUP_CONCAT(tag.tag_id) ) ) );
+------+--------------------------+
| name | GROUP_CONCAT(tag.tag_id) |
+------+--------------------------+
| Jill | 2,3 |
+------+--------------------------+
1 row in set (0.00 sec)
Instead of using IN(), would using FIND_IN_SET() be an option too?
http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_find-in-set
mysql> SELECT FIND_IN_SET('b','a,b,c,d');
-> 2
Here's a full example based on the example problem in the question, confirmed as tested by the asker in an earlier edit to the question:
SELECT name FROM person LEFT JOIN tag ON person.id = tag.person_id GROUP BY person.id
HAVING ( FIND_IN_SET(1, GROUP_CONCAT(tag.tag_id)) ) AND ( FIND_IN_SET(2, GROUP_CONCAT(tag.tag_id)) );
+------+
| name |
+------+
| Bob |
+------+
You can pass a string as array, using a split separator, and explode it in a function, that will work with the results.
For a trivial example, if you have a string array like this: 'one|two|tree|four|five', and want to know if two is in the array, you can do this way:
create function str_in_array( split_index varchar(10), arr_str varchar(200), compares varchar(20) )
returns boolean
begin
declare resp boolean default 0;
declare arr_data varchar(20);
-- While the string is not empty
while( length( arr_str ) > 0 ) do
-- if the split index is in the string
if( locate( split_index, arr_str ) ) then
-- get the last data in the string
set arr_data = ( select substring_index(arr_str, split_index, -1) );
-- remove the last data in the string
set arr_str = ( select
replace(arr_str,
concat(split_index,
substring_index(arr_str, split_index, -1)
)
,'')
);
-- if the split index is not in the string
else
-- get the unique data in the string
set arr_data = arr_str;
-- empties the string
set arr_str = '';
end if;
-- in this trivial example, it returns if a string is in the array
if arr_data = compares then
set resp = 1;
end if;
end while;
return resp;
end
|
delimiter ;
I want to create a set of usefull mysql functions to work with this method. Anyone interested please contact me.
For more examples, visit http://blog.idealmind.com.br/mysql/how-to-use-string-as-array-in-mysql-and-work-with/