MySQL - SELECT until fixed number of rows - mysql

I would like to ask for help because I am not able to execute a SELECT statement in MySQL.
The SELECT should return 350 lines, as long as the first lines are filled according to a specific condition and if there is space left, the rest is filled with another condition.

Use expressions in the ORDER BY clause, and a LIMIT clause.
For example:
SELECT ...
FROM mytable t
ORDER
BY IF(( t.foo >= 117 AND t.bar IN (2,3,5) ),0,1)
, IF(( t.foo >= 0 ),0,1)
, IF(( t.bar = 42 ),0,1)
, ...
LIMIT 350
Rows that satisfy the condition t.foo >= 117 AND t.bar IN (2,3,5) will be ordered first. (Because the ORDER BY will operate on the return from the expression. That condition will be evaluated, and the IF function will return either 0 or 1. The subsequent expressions in the ORDER BY clause will be evaluated in the same way.
The LIMIT clause will restrict the number of rows returned, but doesn't guarantee that the query won't return fewer rows e.g. if mytable contains fewer than 350 rows.

You mean like:
SELECT column(s) FROM TABLE WHERE column = 42 LIMIT 350
Or do you want the first line where 'column = 42' and then read 350 lines?

You limit the number of returned rows with LIMIT. You use ORDER BY to say which rows you prefer.
Let's say you are looking for records where col = 'best', but if there are not enough (i.e. 350) you also want rows with col = 'okay':
select *
from mytable
where col in ('best', 'okay')
order by case when col = 'best' then 1 else 2 end
limit 350;

Related

Optimize query mysql search

I have the following SQL but its execution this very slow, takes about 45 seconds, the table has 15 million record, how can I improve?
SELECT A.*, B.ESPECIE
FROM
(
SELECT
A.CODIGO_DOCUMENTO,
A.DOC_SERIE,A.DATA_EMISSAO,
A.DOC_NUMERO,
A.CF_NOME,
A.CF_SRF,
A.TOTAL_DOCUMENTO,
A.DOC_MODELO
FROM MOVIMENTO A
WHERE
A.CODIGO_EMPRESA = 1
AND A.CODIGO_FILIAL = 5
AND A.DOC_TIPO_MOVIMENTO = 1
AND A.DOC_MODELO IN ('65','55')
AND (A.CF_NOME LIKE '%TEXT_SEARCH%'
OR A.CF_CODIGO LIKE 'TEXT_SEARCH%'
OR A.CF_SRF LIKE 'TEXT_SEARCH%'
OR A.DOC_SERIE LIKE 'TEXT_SEARCH%'
OR A.DOC_NUMERO LIKE 'TEXT_SEARCH%')
ORDER BY A.DATA_EMISSAO DESC , A.CODIGO_DOCUMENTO DESC
LIMIT 0, 100
) A
LEFT JOIN MODELODOCUMENTOFISCAL B ON A.DOC_MODELO = B.CODMODELO
For this query, I would start with an index on MOVIMENTO(CODIGO_EMPRESA, CODIGO_FILIAL, DOC_MODELO) and MODELODOCUMENTOFISCAL(CODMODELO).
That should speed the query.
If it doesn't you may need to consider a full text search to handle the LIKE clauses. I do note that you only have a wildcard at the beginning of one of the patterns. Is that intentional?

MySQL match area code only when given the full number

I have a database that lists a few area codes, area code + office codes and some whole numbers and a action. I want it to return a result by the digits given but I am not sure how to accomplish it. I have some MySQL knowledge but its not very deep.
Here is a example:
match | action
_____________________
234 | goto 1
333743 | goto 2
8005551212| goto 3
234843 | goto 4
I need to query the database with a full 10 digit number -
query 8005551212 gives "goto 3"
query 2345551212 gives "goto 1"
query 3337431212 gives "goto 2"
query 2348431212 gives "goto 4"
This would be similar to the LIKE selection, but I need to match against the database value instead of the query value. Matching the full number is easy,
SELECT * FROM database WHERE `match` = 8005551212;
First the number to query will always be 10 digits, so I am not sure how to format the SELECT statement to differentiate the match of 234XXXXXXX and 234843XXXX, as I can only have one match return. Basically if it does not match the 10 digits, then it checks 6 digits, then it will check the 3 digits.
I hope this makes sense, I do not have any other way to format the number and it has to be accomplished with just a single SQL query and return over a ODCB connection in Asterisk.
Try this
SELECT match, action FROM mytable WHERE '8005551212' like concat(match,'%')
The issue is that you will get two rows in one case .. given your data..
SELECT action
FROM mytable
WHERE '8005551212' like concat(match,'%')
order by length(match) desc limit 1
That should get the row that had the most digits matched..
try this:
SELECT * FROM (
SELECT 3 AS score,r.* FROM mytable r WHERE match LIKE CONCAT(SUBSTRING('1234567890',1,3),'%')
UNION ALL
SELECT 6 AS score,r.* FROM mytable r WHERE match LIKE CONCAT(SUBSTRING('1234567890',1,6),'%')
UNION ALL
SELECT 10 AS score,r.* FROM mytable r WHERE match LIKE CONCAT(SUBSTRING('1234567890',1,10),'%')
) AS tmp
ORDER BY score DESC
LIMIT 1;
What ended up working -
SELECT `function`,`destination`
FROM reroute
WHERE `group` = '${ARG2}'
AND `name` = 0
AND '${ARG1}' LIKE concat(`match`,'%')
ORDER BY length(`match`) DESC LIMIT 1

Select Max and Select other column

I am trying to get the max + 1 value from one column, and all of the values from another column. However, my query does not give any results.
For example,
SectionItemID SectionItem
1 blue
2 red
The query should return
SectionItemID SectionItem
3 blue
red
Heres what I have
SELECT SectionItem,MAX(SectionItemID) + 1 AS SectionItemID FROM Core.SectionItem_Lkup
SELECT SectionItem,
(select MAX(SectionItemID)+1 FROM Core.SectionItem_Lkup) AS SectionItemID
FROM Core.SectionItem_Lkup
Whenever you GROUP BY, you should aggregate the other columns involved.
Mysql does allow to omit aggregation on other colums
MsSQL does not, cause the result is undefined for columns without Aggregation.
Best way is to aggregate other columns. For your szenario, you could use group_concat
SELECT MAX(SectionItemID)+1, Group_concat(SectionItem) FROM tbl
Note: The query does not contain any Group By, because you dont want to group on SectionItemId nor SectionItem. Omiting the Group By and using aggregate-functions will use them on the whole table.
Output:
MAX(SECTIONITEMID)+1 GROUP_CONCAT(SECTIONITEM)
3 blue,red
http://sqlfiddle.com/#!2/353bf3/6
select case when t2.SectionItem = 'blue'
then cast(max(t1.SectionItemID) + 1 as varchar(1))
else '' end
as SectionItemID
, t2.SectionItem
from Core.SectionItem_Lkup t1
full outer join Core.SectionItem_Lkup t2 on 1 = 1
group by t2.SectionItem
order by
case when t2.SectionItem = 'blue'
then cast(max(t1.SectionItemID) + 1 as varchar(1))
else '' end
desc

how can I tell if the last x rows of 'state' = 1

I need help with a SQL query.
I have a table with a 'state' column. 0 means closed and 1 means opened.
Different users want to be notified after there have been x consecutive 1 events.
With an SQL query, how can I tell if the last x rows of 'state' = 1?
If, for example, you want to check if the last 5 consecutive rows have a state equals to 1, then here's you could probably do it :
SELECT IF(SUM(x.state) = 5, 1, 0) AS is_consecutive
FROM (
SELECT state
FROM table
WHERE Processor = 3
ORDER BY Status_datetime DESC
LIMIT 5
) as x
If is_consecutive = 1, then, yes, there is 5 last consecutive rows with state = 1.
Edit : As suggested in the comments, you'll have to use ORDER BY in your query, to get the last nth rows.
And for more accuracy, since you have a timestamp column, you should use Status_datetime to order the rows.
You should be able to use something like this (replace the number in the HAVING with the value of x you want to check for):
SELECT Processor, OpenCount FROM
(
SELECT TOP 10 Processor, DateTime, Sum(Status) AS OpenCount
FROM YourTable
WHERE Processor = 3
ORDER BY DateTime DESC
) HAVING OpenCount >= 10

Random row from big query result

I need to get 1-2 rows from query result retrived with SQL select on indexed columns without getting the whole record set.
For example I will retrieve 10 000 records using query
SELECT * FROM table WHERE field 1>1 AND field1 < 10
but I need only 1 random row from this query regarding to highload of my database.
I can use
SELECT * FROM table WHERE field 1>1 AND field1 < 10 LIMIT 100, 1
But I don't know records numebr to use correct offset range
How can I achieve this goal?
You could use ORDER BY RAND()
SELECT * FROM table WHERE field1 > 1 AND field1 < 10 ORDER BY RAND() LIMIT 1
This will return 1 random row with field1 in between 1 and 10
How about restricting the records you select in the first place?
SELECT * FROM table WHERE field1 IN (CONVERT(RAND()*10,SIGNED),CONVERT(RAND()*10,SIGNED)) LIMIT 2