How to use mysql WHERE IN for two separate tables - mysql

I have two tables
books_tbl:
blocks side-bar top-bar
23,45 3,15 11,56
pages_tbl:
id title
1 ff
3
11
15
I want to select the rows from pages_tbl where pages id has included either blocks, side-bar or tob-bar columns in books_table.
How to process this?

You should really consider fixing your table structure. Never store multiple value in a single cell. See Normalization.
As in this case you can't, try using find_in_set function.
select
from pages_tbl p
where exists (
select 1
from books_tbl b
where find_in_set(
p.id,
concat(b.blocks, ',', b.side_bar, ',', b.top_bar)
) > 0
);
Remember though that this will be slow because the server can't use index if any.

It's usually not a good idea to store comma separated values in a single field. If you really cannot change your data structure, you could use a query like this:
select p.id, p.title
from
pages_tbl p inner join books_tbl b
on (
find_in_set(p.id, b.blocks)
or find_in_set(p.id, b.side-bar)
or find_in_set(p.id, b.top-bar)
)
-- add where condition?
group by p.id, p.title

Related

Trying to use a select query after two with statements

I plan to make two with queries that make two temporary tables, one which gives the sum of the remaining loan payments, and one that gives the sum of all the transactions in the table. I've tested the two with statements and they work by themselves, however trying to perform a select query with them only seems to return errors.
WITH RemainingLoans AS(SELECT SUM(TIMESTAMPDIFF(MONTH, l.NextPayment, l.FullPaymentConfirmed) * l.MonthlyPaymentRate) AS RemainingPayments FROM loans AS l);
WITH CurrentBalances AS(SELECT SUM(t.amount) AS allBalances FROM transactions AS t);
SELECT l.RemainingPayments - b.allBalances AS TotalOutstandings FROM RemainingLoans AS l, CurrentBalances AS b;
The first with is called RemainingLoans with one attribute RemainingPayments, and the second with is called CurrentBalances with one attribute allBalances. To my knowledge these should work like tables which is why I attempted my select clause on the third line, however I am currently getting syntax errors. Is there a correct way to format my select statement?
This should be a single statement, not multiple statements.
The fiddle
WITH list elements are separated by a comma. There's only one WITH keyword at the beginning of the list.
The semicolon goes at the end of the entire statement, not after the WITH list elements.
Here's the adjusted statement:
WITH RemainingLoans AS (
SELECT SUM(TIMESTAMPDIFF(MONTH, l.NextPayment, l.FullPaymentConfirmed) * l.MonthlyPaymentRate) AS RemainingPayments
FROM loans AS l
)
, CurrentBalances AS (
SELECT SUM(t.amount) AS allBalances
FROM transactions AS t
)
SELECT l.RemainingPayments - b.allBalances AS TotalOutstandings
FROM RemainingLoans AS l
, CurrentBalances AS b
;

mysql query for long query to execute in stored procedure

I got a hash map in java like this
{(1,'2018-06-29 10:19:33'),(4,'2018-06-29 10:19:34'),(10,'2018-06-29 10:19:38'),....}
The length of map could go as high as 3000
and a mysql table
id name updated
1, firstProduct, 2018-06-29 09:19:33
2, secondproduct, 2014-06-29 10:19:33
4, fourthproduct, 2016-06-29 09:19:33
10, tenthproduct, 2018-06-29 06:13:32
.......
the key in the map is a id field in the table and the value is the updated timestamp field.
I would like to get all the products in the table whose timestamp is greater that value in the map.
like
select * from products where id = 1 and updated > '2018-06-29 10:19:33'
select * from products where id = 4 and updated > '2018-06-29 10:19:34'
...
But there could be as many as 3000 entries in the map.
I am thinking of passing the map values to mysql stored procedure. Inside the procedure a while loop will execute select statement for each map entry into a result set and finally return the result set back to java program.
Would like to know if this is possible and i feel there is a better solution for this but cant figure out.
I would dynamically generate a statement in Java.
Either:
SELECT p.id, p.name, p.update
FROM products p
WHERE 1=0
OR ( p.id = ? AND updated > ? )
OR ( p.id = ? AND updated > ? )
OR ( p.id = ? AND updated > ? )
(MySQL likely won't make effective use of an index for that query.)
Or, we could do :
SELECT p.id, p.name, p.update FROM products p WHERE p.id = ? AND updated > ?
UNION ALL
SELECT p.id, p.name, p.update FROM products p WHERE p.id = ? AND updated > ?
UNION ALL
SELECT p.id, p.name, p.update FROM products p WHERE p.id = ? AND updated > ?
With an appropriate index defined, each SELECT could make effective use of that. But with this approach, we are probably going to hit an upper limit on the number of table references in a single query. So this approach may need to be broken up into chunks.
Personally, I wouldn't hide the complexity in a database procedure.
It's not clear what benefit we would gain by implementing a database procedure.

Using column value as clause for IN MySql

I don't understand why this doesn't work, I have a column where I store values comma separated in my "Mysql" database then I want to join two tables to give me results. eg:
SELECT *
FROM users u INNER JOIN
groups g
ON u.id IN ( g.ownerId )
WHERE u.active='1' AND g.gid='15';
And the value of g.ownerId in this senerio is '175,178'.
For some reason this only returns the results from the join with ownerId 175. BUT if I manually enter the values ( 175, 178 ) in the IN clause BOTH rows show up. Why isn't it using both values in the ownerId column?
I have tried this to "separate" the values or force a "list" but it didn't work...
SELECT * FROM users u INNER JOIN groups g ON u.id IN ( SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(g.ownerId, ',', 1), ' ', -1) as x,
SUBSTRING_INDEX(SUBSTRING_INDEX(g.ownerId, ',', 2), ' ', -1) as y ) where g.groupId='15'
Has anyone experienced this before or know what to do?
It doesn't work because the in value consists of a list with a single element that happens to have a comma in it. It is equivalent to:
on uid = '175,178'
You can replace the logic with find_in_set():
on find_in_set(uid, g.id) > 0
However, you really should learn about junctions tables and why your data structure is bad, bad, bad:
You are storing numbers as strings.
You have foreign key relationships with no way to declare them.
You are using string operations inappropriately.
Your query cannot make use of an index.
Fix the data structure.

Get a list of ids not present in a table

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.

How to efficiently code a query in mysql to AND tags?

I have a common problem to be sure. I'd like to make a query that finds an entity that has "n" tags. So in the simplest case, we find all the entities that have the tag "hey". In a more complex case, we find all the entities that have all the tags "hey", "hi" and "howdy".
It seems that I have to join to the tag table 3 times, and and thus create 3 different aliases. In the abstract case, I will have to make N different aliases. Is there a simpler way to achieve this?
The reason I am asking is that I need to write a query that not only does this for tags, but for a variety of things. So I am basically going to join NxM aliases... which is going to suck to write (and tune) the query.
Help?
EDIT:
Nevermind. I found the solution:
select distinct g.id, g.description
FROM gallery g
inner join gallery_to_tag g2t_0
on g2t_0.gallery_id = g.id
inner join tag t_0
on t_0.id = g2t_0.tag_id and t_0.term = 'hi'
inner join gallery_to_tag g2t_1
on g2t_1.gallery_id = g.id
inner join tag t_1
on t_1.id = g2t_1.tag_id and t_1.term = 'hey'
Is this what you might be looking for. Its hard to tell without out seeing your schema
CREATE TEMPORARY TABLE `checktags` (
`checkme` varchar(100) NOT NULL,
KEY `checkme` (`checkme`)
) ENGINE=MyISAM;
//INSERT ALL TAGS TO CHECK
SELECT * FROM `table`
LEFT JOIN `tags` ON `table_id` = `tag_table_id`
WHERE `tag` IN (SELECT `checkme` FROM `checktags`);
It is difficult to provide a precise answer without the schema, however, I believe you are asking how to determine that a given item has all the tags being queried. You could do something like
Select ..
From MainTable
Where Exists (
Select 1
From TagsTable
Where TagsTable.FK = MainTable.PK
And TagsTable.Tag In('hey','hi','howdy')
Having Count(*) = 3
)
If you want to avoid joining tables, you will need some subqueries. So for N tags, you would need N subqueries.
SELECT * FROM Entities
WHERE id IN (SELECT entity_id FROM tags WHERE tag = 'Hey')
AND id IN (SELECT entity_id FROM tags WHERE tag = 'Hello')
AND ...
And the same way, you can select entities that have any of some desired tags:
SELECT * FROM Entities
WHERE id IN (SELECT entity_id FROM tags WHERE tag = 'Hey')
OR id IN (SELECT entity_id FROM tags WHERE tag = 'Hello')
OR ...