SQL MATCH ... AGAINST limits result to current year - mysql

I'm stumped by this:
Two commands:
SELECT Date,Sentence FROM exampletable;
SELECT Date,Sentence FROM exampletable WHERE MATCH (Sentence) AGAINST ("South" IN NATURAL LANGUAGE MODE );
The first gives me results for the entire database, beginning in 2013. I see that there's an entry sometime in 2018 that contains the word "South", so using a match against in the second command I know I should get at least one result pre 2020. However, the first result is from 2020-01-28 onwards.
This happens in all examples I try. Simply adding a match against limits my returned results to > 2020. Is there some database setting that I'm not aware of? Or just something plainly obvious?
Any help would be appreciated! (I'm using MySQL 5.7)

Your query has no order by. Have you tried something like this?
SELECT Date, Sentence
FROM exampletable
WHERE MATCH (Sentence) AGAINST ("South" IN NATURAL LANGUAGE MODE )
ORDER BY date;
Perhaps the earlier dates are just later in the result set.

Related

MySQL 5.7 RAND() and IF() without LIMIT leads to unexpected results

I have the following query
SELECT t.res, IF(t.res=0, "zero", "more than zero")
FROM (
SELECT table.*, IF (RAND()<=0.2,1, IF (RAND()<=0.4,2, IF (RAND()<=0.6,3,0))) AS res
FROM table LIMIT 20) t
which returns something like this:
That's exactly what you would expect. However, as soon as I remove the LIMIT 20 I receive highly unexpected results (there are more rows returned than 20, I cut it off to make it easier to read):
SELECT t.res, IF(t.res=0, "zero", "more than zero")
FROM (
SELECT table.*, IF (RAND()<=0.2,1, IF (RAND()<=0.4,2, IF (RAND()<=0.6,3,0))) AS res
FROM table) t
Side notes:
I'm using MySQL 5.7.18-15-log and this is a highly abstracted example (real query is much more difficult).
I'm trying to understand what is happening. I do not need answers that offer work arounds without any explanations why the original version is not working. Thank you.
Update:
Instead of using LIMIT, GROUP BY id also works in the first case.
Update 2:
As requested by zerkms, I added t.res = 0 and t.res + 1 to the second example
The problem is caused by a change introduced in MySQL 5.7 on how derived tables in (sub)queries are treated.
Basically, in order to optimize performance, some subqueries are executed at different times and / or multiple times leading to unexpected results when your subquery returns non-deterministic results (like in my case with RAND()).
There are two easy (and likewise ugly) workarounds to get MySQL to "materialize" (aka return deterministic results) these subqueries: Use LIMIT <high number> or GROUP BY id both of which force MySQL to materialize the subquery and return the expected results.
The last option is turn off derived_merge in the optimizer_switch variable: derived_merge=off (make sure to leave all the other parameters as they are).
Further readings:
https://mysqlserverteam.com/derived-tables-in-mysql-5-7/
Subquery's rand() column re-evaluated for every repeated selection in MySQL 5.7/8.0 vs MySQL 5.6

Get only newer Records from MySQL Table, filtered by date attributes

I would like to filter out old records and present only newer ones. The idea is currentDate minus 2 years. One record looks like this (table Symposium):
Attributes:
ID;Day;Month;Year;Firstname;Lastname;Symposium_title;Speakers;
Records
1;26;10;2012;Markus;Meier;Topic MySQL;5;
3;26;10;2011;Markus;Meier;Topic PHP;5;
6;26;01;2010;Markus;Meier;Topic CSS;5;
Wished output
1;26;10;2012;Markus;Meier;Topic MySQL;5;
3;26;10;2011;Markus;Meier;Topic PHP;5;
I could easily do a small php to filter out older data, but I'm sure there is a way to do it direct with mysql in one command.
some query like this (this is just pseudo code)
SELECT * FROM Symposium WHERE (current_data() - 2 Years);
remark: The attributes day;month;year will not be changed. There are more then 50 tables, that are build up by this attributes. So don't recommend change of the table.
Can someone help me ?
You can use STR_TO_DATE function and DATE_ADD for this task:
syntax:
STR_TO_DATE(string, format)
So in your code:
SELECT * from Symposium
WHERE DATE_ADD(STR_TO_DATE(concat(Day,'-',Month,'-',Year),'%d-%m-%Y'), INTERVAL 2 YEAR) > NOW();
(sadly, I don't have a MySQL at hand right now, so I can't test it, but unless there is some very basic typo in it, it should work)

ORDERBY "human" alphabetical order using SQL string manipulation

I have a table of posts with titles that are in "human" alphabetical order but not in computer alphabetical order. These are in two flavors, numerical and alphabetical:
Numerical: Figure 1.9, Figure 1.10, Figure 1.11...
Alphabetical: Figure 1A ... Figure 1Z ... Figure 1AA
If I orderby title, the result is that 1.10-1.19 come between 1.1 and 1.2, and 1AA-1AZ come between 1A and 1B. But this is not what I want; I want "human" alphabetical order, in which 1.10 comes after 1.9 and 1AA comes after 1Z.
I am wondering if there's still a way in SQL to get the order that I want using string manipulation (or something else I haven't thought of).
I am not an expert in SQL, so I don't know if this is possible, but if there were a way to do conditional replacement, then it seems I could impose the order I want by doing this:
delete the period (which can be done with replace, right?)
if the remaining figure number is more than three characters, add a 0 (zero) after the first character.
This would seem to give me the outcome I want: 1.9 would become 109, which comes before 110; 1Z would become 10Z, which comes before 1AA. But can it be done in SQL? If so, what would the syntax be?
Note that I don't want to modify the data itself—just to output the results of the query in the order described.
This is in the context of a Wordpress installation, but I think the question is more suitably an SQL question because various things (such as pagination) depend on the ordering happening at the MySQL query stage, rather than in PHP.
My first thought is to add an additional column that is updated by a trigger or other outside mechanism.
1) Use that column to do the order by
2) Whatever mechanism updates the column will have the logic to create an acceptable order by surrogate (e.g. it would turn 1.1 into AAA or something like that).
Regardless...this is going to be a pain. I do not evny you.
You can create function which have logic to have human sort order like
Alter FUNCTION [dbo].[GetHumanSortOrder] (#ColumnName VARCHAR(50))
RETURNS VARCHAR(20)
AS
BEGIN
DECLARE #HumanSortOrder VARCHAR(20)
SELECT #HumanSortOrder =
CASE
WHEN (LEN(replace(replace(<Column_Name>,'.',''),'Figure ',''))) = 2
THEN
CONCAT (SUBSTRING(replace(replace(<Column_Name>,'.',''),'Figure ',''),1,1),'0',SUBSTRING(replace(replace(<Column_Name>,'.',''),'Figure ',''),2,2))
ELSE
replace(replace(<Column_Name>,'.',''),'Figure ','')
END
FROM <Table_Name> AS a (NOLOCK)
WHERE <Column_Name> = #ColumnName
RETURN #HumanSortOrder
END
this function give you like 104,107,119,10A, 10B etc as desired
And you can use this function as order by
SELECT * FROM <Table_Name> ORDER BY GetHumanSortOrder(<Column_Name>)
Hope this helps

MySQL using table columns in function to create alias to be used in sorting

It sounds more complicated than it actually is. Here is what I'm trying to do within the SELECT part:
SELECT TIMESTAMPADD(
UCASE(
SUBSTRING(offset_unit,1,CHAR_LENGTH(offset_unit)-1)
),1,'2003-01-02') as offset_date
offset_unit is a VARCHAR column in the database. It contains one of the following: "Hours","Minutes".
offset is an INT.
I am trying to convert the offset_unit to uppercase, after I have removed the last character ('s') so I can have a proper interval (MINUTE, HOUR...) so I can get a date that I can use in sorting afterwards, but MySQL keeps throwing an error. I have tested each step by adding one function at a time, and it only fails after I add TIMESTAMPADD. If I enter MINUTE manually then it works.
Any way to get this working?
Additional info: I am running this in CakePHP 1.3, in a find, within the 'fields' array, but that shouldn't be important.
this can be easily achived by using CASE WHEN clause as:
SELECT (CASE
WHEN offset_unit = 'HOURS'
THEN TIMESTAMPADD(HOUR,`offset`,'2003-01-02')
WHEN offset_unit = 'MINUTES'
THEN TIMESTAMPADD(MINUTE,`offset`,'2003-01-02')
END) AS offset_date
FROM my_table;
SEE SQLFIDDLE DEMO HERE
It doesn't work because TIMESTAMPADD does not take a string as the first argument, but a unit keyword, for example MINUTE. My guess is that you need to do this in two steps, first get the unit and then construct a query with the correct keyword.

Trying to use BETWEEN condition to return rows based on date but getting no results

I have a database containing a list of events, it is formatted something like this:
Datef Event Location Discipline
10/01/2012 MG Training Brooklands MG
I am running this query in order to get the results between certain dates:
SELECT * FROM events WHERE Discipline IN ('MG') AND Datef BETWEEN 01/01/2012 AND 31/01/2012
The query runs correctly and I know that there are relevant results in the database, but I receive no results when running the query in phpmyadmin (I just get told "Your SQL query has been executed successfully").
I was wondering if anyone had any idea why this wouldn't be returning results?
Update:
Putting dates in quotes (e.g. SELECT * FROM events WHERE Discipline IN ('MG') AND Datef BETWEEN 01/01/2012 AND 31/01/2012) kinda works but there's a bug.
I've certain dates doesn't work. e.g. SELECT * FROM events WHERE Discipline IN ('COMM') AND Datef BETWEEN '2012-02-01' AND '2012-02-29' shows no results, even though there is an event on 2010-02-01. Is this a peculiarity in the BETWEEN algorithm, or am I still getting my query wrong?
Without quotes or anything designating those values as dates, it will simply do the math on the integers you wrote.
In other words, you ask for
BETWEEN 01/01/2012 AND 31/01/2012
So you get 1/1=1, then 1/2012 which is almost 0.
Then you do 31/1=31, then 31/2012 which is also almost 0.
So it becomes
BETWEEN 0 and 0
Try wrapping your code strtotime(). MySQL and PHP use different formatting.
For some additional info, here are a couple of links:
http://www.richardlord.net/blog/dates-in-php-and-mysql
http://www.binarytides.com/blog/parse-and-format-dates-between-php-and-mysql/
Your column Datef is of the wrong type and should be datatime
SELECT
*
FROM
`events`
WHERE
`Discipline` IN ('MG')
AND
`Datef` BETWEEN '2012-01-01' AND '2012-01-31'