MySQL request WHERE ... IN - sql

in a table "partners", i've a field "sites" which can contain values like 1,27,38,12
then, in a website which has ID n°27, i would like to get partners associated to this website.
I tried this :
SELECT * FROM partners WHERE 27 IN (partners.sites)
It works if 27 is at the beginning of the string (eg: 27,1,128) but it doesn't work if 27 is in the middle (eg: 1,27,38,12)
Have you got any idea to manage this ?
Thanks.
Cyril

see the manual for find_in_set

This doesn't make any sense
Why not make
select * from partners where sites=27?
Or are you suggesting that sites is a varchar containing CSV?
In this case this is totally wrong from any perspective. Do a one-to-many relationship in your database.

You may want to use the FIND_IN_SET() function, because the IN() function will not expect a comma-separated string as an argument.
This does not work:
SELECT 27 IN ('1,27,5');
+------------------+
| 27 IN ('1,27,5') |
+------------------+
| 0 |
+------------------+
This works:
SELECT FIND_IN_SET(27, '1,27,5') > 0;
+-------------------------------+
| FIND_IN_SET(27, '1,27,5') > 0 |
+-------------------------------+
| 1 |
+-------------------------------+
1 row in set (0.00 sec)

SELECT * FROM partners WHERE partners.sites like '%27%'

I would have to agree that using relationships will not only be better practice, but will optimize your database request speeds as well, even if it's non noticeable, every bit counts.
So assuming you had a separate table called sites, you could do a call like follows:
SELECT * FROM partners WHERE pid IN (SELECT spid FROM sites WHERE siteid = 27);
Your relationship could then be something like:
-------------------------------------
PARTNERS
-------------------------------------
pid | some field |
2 | |
-------------------------------------
-------------------------------------
SITES
-------------------------------------
spid | siteid | surl
2 | 27 | http://...
-------------------------------------

Assuming sites is a field in the same table you're querying, you could try this:
SELECT * FROM partners WHERE sites LIKE %27;
SELECT * FROM partners WHERE sites LIKE 27;
Does that work?

Related

How to compare value with multiple modified values from another table in BigQuery?

I am using Google BigQuery and I got the following issue:
I have a table (A) like this:
| time | request |
|------------------------|-----------------|
|2019-09-24 11:10:00 UTC | fakewebsite.com |
|2019-09-24 11:10:00 UTC | realwebsite.com |
|........................|.................|
|2019-09-24 11:10:00 UTC | foobwebsite.com |
|2019-09-24 11:10:00 UTC | barrwebsite.com |
And another table (B) like this:
| blacklist |
|---------------|
| foo.com |
| ... |
| bar.com |
I want to make a query that will grab a modified version of the values inside the blacklist field of table B as follows:
SPLIT(NET.REG_DOMAIN(blacklist), CONCAT('.',NET.PUBLIC_SUFFIX(blacklist)))[OFFSET(0)] AS to_exclude --this will return only "foo" from "foo.com"
and then return all values from the request field of table A where none of the to_exclude was found.
I know how to do this for one value but I don't know how to do this for multiple. I am looking for something like the following:
#standardSQL
WITH tmp_blacklist AS
(SELECT
SPLIT(NET.REG_DOMAIN(blacklist), CONCAT('.',NET.PUBLIC_SUFFIX(blacklist)))[OFFSET(0)] AS to_exclude
FROM
mydataset.B)
SELECT
request
FROM
mydataset.A
WHERE
request NOT LIKE ("%value1%", "%value2%", ..., "%valuen%") -- I can't use OR along with the NOT LIKE since the values are too many and they will change.
The n values are the values of the tmp_blacklist table.
Also if I don't define the table with the WITH and I define it after the NOT LIKE I am going to get the following error: Scalar subquery produced more than one element which makes sense if LIKE expects only one element. But then again that's half of the job done if it get's fixed since I want the "%value%" and not just the value of the table.
Now I searched online for a way to do this and I found people saying that it can't be done and then some workarounds with combinations of LIKE and IN where people said it will be very slow if one of the tables grows to have tons of data(my case).
What is the best way to do this?
One method uses not exists:
SELECT a.request
FROM mydataset.A a
WHERE NOT EXISTS (SELECT 1
FROM tmp_blacklist bl
WHERE a.request LIKE CONCAT('%', bl.to_exclude, '%'
);
Note that this can be expensive. You might want to test constructing the exclusion string as:
'value1|value2|value3'
and then using regular expressions.

Postgres matching against an array of regular expressions

My client wants the possibility to match a set of data against an array of regular expressions, meaning:
table:
name | officeId (foreignkey)
--------
bob | 1
alice | 1
alicia | 2
walter | 2
and he wants to do something along those lines:
get me all records of offices (officeId) where there is a member with
ANY name ~ ANY[.*ob, ali.*]
meaning
ANY of[alicia, walter] ~ ANY of [.*ob, ali.*] results in true
I could not figure it out by myself sadly :/.
Edit
The real Problem was missing form the original description:
I cannot use select disctinct officeId .. where name ~ ANY[.*ob, ali.*], because:
This application, stored data in postgres-xml columns, which means i do in fact have (after evaluating xpath('/data/clients/name/text()'))::text[]):
table:
name | officeId (foreignkey)
-----------------------------------------
[bob, alice] | 1
[anthony, walter] | 2
[alicia, walter] | 3
There is the Problem. And "you don't do that, that is horrible, why would you do it like this, store it like it is meant to be stored in a relation database, user a no-sql database for Document-based storage, use json" are no options.
I am stuck with this datamodel.
This looks pretty horrific, but the only way I can think of doing such a thing would be a hybrid of a cross-join and a semi join. On small data sets this would probably work pretty well. On large datasets, I imagine the cross-join component could hit you pretty hard.
Check it out and let me know if it works against your real data:
with patterns as (
select unnest(array['.*ob', 'ali.*']) as pattern
)
select
o.name, o.officeid
from
office o
where exists (
select null
from patterns p
where o.name ~ p.pattern
)
The semi-join helps protect you from cases where you have a name like "alicia nob" that would meet multiple search patterns would otherwise come back for every match.
You could cast the array to text.
SELECT * FROM workers WHERE (xpath('/data/clients/name/text()', xml_field))::text ~ ANY(ARRAY['wal','ant']);
When casting a string array into text, strings containing special characters or consisting of keywords are enclosed in double quotes kind of like {jimmy,"walter, james"} being two entries. Also when matching with ~ it is matched against any part of the string, not the same as LIKE where it's matched against the whole string.
Here is what I did in my test database:
test=# select id, (xpath('/data/clients/name/text()', name))::text[] as xss, officeid from workers WHERE (xpath('/data/clients/name/text()', name))::text ~ ANY(ARRAY['wal','ant']);
id | xss | officeid
----+-------------------------+----------
2 | {anthony,walter} | 2
3 | {alicia,walter} | 3
4 | {"walter, james"} | 5
5 | {jimmy,"walter, james"} | 4
(4 rows)

Oracle CONTAINS query not returning results

I have a table called products with the following schema and data:
| product_id | name | description | price | location |
| NUMBER | VARCHAR2 | CLOB |NUMBER(9,2)| SDO_GEOMETRY |
--------------------------------------------------------------------------
| 27 | Nexus 4 | Android phone | 160 | null |
When I issue a SELECT * FROM products; query, I get the data back. All is well. But I want to be able to get results back using CONTAINS() in a where, like this:
SELECT "PRODUCT_ID", "NAME", "DESCRIPTION", "PRICE"
FROM "PRODUCTS"
WHERE CONTAINS("NAME", 'nexus') > 0;
However I'm getting no results back. The same thing happens when I change nexus to Nexus or Nexus 4. I thought it might be something to do with name being a resolved word, but the same thing happens with the description column.
Turns out this is because I had two text indexes on the same table, for name and description. I removed the one for description and it worked.
If you don't use mixed/lower case table and column names, all of the " characters can be removed in your query ...
SELECT product_id, name, description, price FROM product WHERE CONTAINS(name, '%Nexus%') > 0;

mysql - speedup regex

I have a table:
+--------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+------------------+------+-----+---------+----------------+
| idurl | int(11) | NO | PRI | NULL | auto_increment |
| idsite | int(10) unsigned | NO | MUL | NULL | |
| url | varchar(2048) | NO | | NULL | |
+--------+------------------+------+-----+---------+----------------+
the select statement is:
SELECT idurl,
url
FROM URL
WHERE idsite = 34
AND url REGEXP '^https\\://www\\.domain\\.com/checkout/step_one\\.php.*'
The query needs 5 seconds on a table with 1000000 rows.
Can I achieve a speedup with indexes or something else?
Looks like a LIKE might suffice. LIKE uses % as a wildcard for any number of characters.
AND url LIKE 'https://www.domain.com/checkout/step_one.php%'
LIKE does not require a starting anchor like ^. Only the second example would match:
'Sherlock and Watson' LIKE 'and%'
'Sherlock and Watson' LIKE '%and%'
'Sherlock and Watson' LIKE '%and'
Any index involving the URL column is likely not going to help you because the database engine still has to walk through the contents of that column to check whether the contents match the regex.
What may help you, depending on how many unique values of IDSITE you have, is to either place an index on IDSITE or do an initial select WHERE IDSITE = 34, and use that subquery as the target of your query on URL.
Something like:
select
idurl,
url
from
(select idurl, url from uwe_url where idsite = 34)
where
url REGEXP '^https\\://www\\.domain\\.com/checkout/step_one\\.php.*'
But I'm pretty sure you can't get around the text parsing for the URL column match.
You could use the LIKE operator instead of a regular expression. But as your regular expression is simple, this may or may not improve performance.
You could split out the domain into a separate field, index it and use that in your where clause. If the URLs that you store are from many different domains then such an index could improve performance considerably.
Looks like you don't really need that REGEXP.
This clause should suffice:
AND eu.url LIKE 'https://www.domain.com/checkout/step_one.php%'

CONTAINS sql function doesn't match underscores

I have some table 'TableName' like Id,Name:
1 | something
2 | _something
3 | something like that
4 | some_thing
5 | ...
I want to get all rows from this table where name containes 'some'.
I have 2 ways:
SELECT * FROM TableName WHERE Name like '%some%'
Result is table :
1 | something
2 | _something
3 | something like that
4 | some_thing
But if I use CONTAINS function
SELECT * FROM TableName WHERE CONTAINS(Name,'"*some*"')
I get only
1 | something
3 | something like that
What should I do to make CONTAINS function work properly?
The last time I looked (admittedly SQL Server 2000) CONTAINS didn't support wildcard matching at the beginning of words, only at the end. Also, you might need to check your noise files to see if the "_" character is being ignored.
Also see
How do you get leading wildcard full-text searches to work in SQL Server?
http://doc.ddart.net/mssql/sql70/ca-co_15.htm
If you read this article you will see that * means prefix this means that word must start with this, but like means the word contains key phrase.
Best Regards,
Iordan
Try this:
SELECT * FROM TableName WHERE CONTAINS(Name,'some')