mySQL - FIND_IN_SET() doesn't find the value - php

I m trying to get posts which includes a spesific tag.
The tag row content
,iphone|1468338028,,android|1468338028,,blackberry|1468338028,
query
SELECT * FROM shares WHERE FIND_IN_SET(tag, 'iphone') > 0 ORDER BY DATE DESC limit 10
What is the correct way to do it ?

Your tag is iphone|1468338028 and you look for iphone. That does not match.
Replace the | with , to separate the values.
SELECT * FROM shares
WHERE FIND_IN_SET(replace(tag, '|', ','), 'iphone') > 0

Another alternative is to use LIKE "%text%", if you're not required to use FIND_IN_SET().
SELECT * FROM shares
WHERE tag LIKE "%iphone%"
ORDER BY DATE DESC limit 10
Above snippet should achieve the same, thus avoiding replacing and trimming issues.

Related

Return the string equivalent of a SELECT that only returns one value

I have a SELECT query that only returns one value (not one row, but just one "thing"). It looks like
SELECT IF( EXISTS( SELECT * FROM `Blah` WHERE <whatever> ), 1, 0);
I tried fiddling around with mysqli_result::fetch_assoc, mysqli_result::fetch_object and mysqli_result::fetch_array, and all of them are being really weird. Is there a mysqli_result::fetch_string for special cases like this that just outputs a string on which I can just call intval?
You can do:
SELECT IF( EXISTS( SELECT * FROM `Blah` WHERE <whatever> ), 1, 0) AS exists;
And use any of the functions above to get row number 0's 'exists' column.
Aswell as casraf's answer, another option might be to incorporate a count into this - you might want to find out just how many blah's match your criteria later. Might be easier to read back when you re-visit your code in a years time, too.
SELECT count(*) cnt FROM `Blah` WHERE <whatever>
You'd be able to do a boolean check on the "cnt" variable (i.e. a count of 0 would == false) but also use it to find out how many matches you've got.

MYSQL search for specific word or number in field excluding words or numbers containing those

I am searching welds.welder_id and welds.bal_welder_id which are lists of unique welder IDs separated by spaces by the users.
The record set looks like 99,199,99 w259,w259 259 5-a
99,199,259,5-a and w259 are unique welder id numbers
I cannot use the MYSQL INSTR() function by itself as a search for "99" will pull up records with "199"
Users on each project format their welder IDs a different way (000,a000,0aa) usually to match their customer's records.
I really want to avoid using PHP code for a number of reasons.
To select records with "w259" in the welder_id OR in the bal_welder_id columns, my query looks like this.
SELECT * FROM `welds`
WHERE `omit`=0
AND( (`welder_id`='w259' OR `bal_welder_id`='w259')
OR (`welder_id` LIKE 'w259 %' OR `bal_welder_id` LIKE 'w259 %')
OR (`welder_id` LIKE '% w259' OR `bal_welder_id` LIKE '% w259')
OR (INSTR(`welder_id`, ' w259 ') > 0 OR INSTR(`bal_welder_id`,' w259 ') > 0))
ORDER BY `date_welded` DESC
LIMIT 100;
It works but it takes 0.0030 seconds with 1300 test records on my workstation's SSD.
The actual DB will have hundreds of thousands after a year or two.
Is there a better way?
Thanks.
If I understand your question correctly, one option is to use FIND_IN_SET(str, strlist) string function, which returns the position of the string str in the comma separated string list strlist, for example:
SELECT FIND_IN_SET('b','a,b,c,d');
will return 2. Since your string is not separated by commas, but by spaces, you could use REPLACE() to replace spaces with commas. Your query can be like this:
SELECT * FROM `welds`
WHERE
`omit`=0
AND
(FIND_IN_SET('w259', REPLACE(welder_id, ' ', ','))>0
OR
FIND_IN_SET('w259', REPLACE(bal_welder_id, ' ', ','))>0)
The optimizer however cannot to much, since FIND_IN_SET cannot make use of an index, if present. I would suggest you to normalize your table, if it is possible.

I want to write a query which name having first character having a or b or c or c-g

I want to write a query which name having first character having a or b or c or c-g.
I have list of name with alphabetical order A-Z. i want to filter the by alphabetical order in 3 steps A-G, G-M, N-Z.
By clicking A-G the record shows the name which first character starting from A-G
mysql_query("select * from users where name like "A%" or name like "B%" or name like "C%" or name like "D%" or name like "E%" or name like "F%" or name like "G%"");
But i don't want to write the like several time
so is there any easy way instead of writing like several time.
You can try
mysql_query("select * from users where LOWER(SUBSTR(name, 1, 1)) IN ('a','b','c','d','e','f','g')");
REGEXP could work well here:
SELECT ........ WHERE `name` REGEXP '^[a-g]'
Alternatively, to make better use of indexes:
... WHERE `name` < 'G'
There are ways to achieve this:
First: you can do it with .. OR LIKE .. syntax, like you've described.
Second: use SUBSTRING() to pass into IN operator:
SELECT * FROM t WHERE SUBSTRING(name, 1,1) IN ('A', 'B', 'C')
or use ORD()
SELECT * FROM t WHERE ORD(SUBSTRING(name, 1,1)) BETWEEN ORD('A') AND ORD('C')
Third: use REGEXP:
SELECT * FROM t WHERE name REGEXP '^[ABC]'

MySQL wildcard return only matches with hyphen and number

In my database I have the following rows which will increment if it's a duplicate:
foo
foo-1
foo-2
foo-3
f
f-1
f-2
f-3
bar
bar-1
I want to query the db and get the last f-#. I've tried using the LIKE operator below:
SELECT * FROM links WHERE slug LIKE '$slug%' ORDER BY timestamp DESC LIMIT 1";
My Problem
If $slug == f it returns foo-3 rather than f-3. Is there a better way to use the % wildcard?
SELECT *
FROM links
WHERE slug LIKE '$slug-%' OR slug = '$slug'
ORDER BY timestamp DESC
LIMIT 1
The alternative, if you didn't want to do an OR, would be to use a REGEXP match. However, you might give up the ability to use an index for the query if you do that.

Make multiple pages out of a mysql query

So, i have this database right, with some fields called 'id', 'title' and 'message'. Now i got like 700 messages in the database. So all i wanna do, is set a limit of max 50 message title's per page, and make multiple pages... How can i do that?
I only know to get the first page, using LIMIT...
As you guessed, you have to use the LIMIT keyword.
It accepts two value (quoting) :
the offset of the first row to return
the maximum number of rows to return
In your case, you'll have to use something like this for the first page :
select * from your_table order by ... limit 0, 50
And, then, for the second page :
select * from your_table order by ... limit 50, 50
And for the third one :
select * from your_table order by ... limit 100, 50
And so on ;-)
Edit after the comment : to get the page number, you'll have to receive it from your URLs, that would look like this :
http://www.example.com/page.php?pagenum=2
Then, you'll calculate the first value for the limit, :
$offset = 50 * intval($_GET['pagenum']);
And inject it in your query :
select * from your_table order by ... limit $offset, 50
Constructing URLs to the differents pages is now a matter of getting URLs such as these :
http://www.example.com/page.php?pagenum=0
http://www.example.com/page.php?pagenum=1
http://www.example.com/page.php?pagenum=2
...
If you know you have 700 elements, and 50 per page, you'll have 700/50 pages ;-)
So, something like this should do the trick :
for ($i=0 ; $i<700/50 ; i++) {
// Use http://www.example.com/page.php?pagenum=$i as URL
}
Of course, 700 is a value that can probably change, and should not be hard-coded : it should be determined from the database, using a count query :
select count(*) as total
from your_table
...
Your PHP file may receive a GET argument being the page number.
Then you do your query with LIMIT ($page_number * $messages_per_page), $messages_per_page (pseudo-code).
$messages_per_page = 50 in your case. $page_number is deduced from a GET argument, after sanitizing, the first page being page number 0.

Categories