Select Result only if unique (sort of) - mysql

I am building a simple sql query, though I cant get my head around this one.
This is the layout for the table:
Challange: I would like to grap all from this table, only if there is an entry (by id_order) which does not have a threshold of 20 (which in this case, only ID 18 should be shown dynamically).
I was thinking going with:
SELECT * FROM `cancelorders_history` WHERE threshold != 20 GROUP BY `id_order`
Though this throws following error (and Im not sure that the query is matching the logic Im looking for, like explained above):
Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'exampletable.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
I cant use:
SELECT * FROM `cancelorders_history` WHERE threshold != 20
Because gives me both ID of 13,18,19.
What would be the preferred method to go around this?

Hmmm . . . I think you can use not exists:
select coh.*
from cancelorders_history coh
where not exists (select 1
from cancelorders_history coh2
where coh2.id_order = coh.id_order and coh2.threshold >= 20
);
Or, use a window function:
select coh.*
from (select coh.*,
max(threshold) over (partition by id_order) as max_threshold
from cancelorders_history coh
) coh
where max_threshold < 20;

You have an error on the GROUP BY because you have to have a group for every column you SELECT. Code should be something like:
SELECT * FROM cancelorders_history WHERE threshold != 20 GROUP BY threshold, notification_sent, id_order, id;
Yet, your query does not meet the requirements to only get one result. Doesn't look like want to use GROUP BY. Perhaps ORDER BY, but you'll have to explain the logic you really want to use.

Related

SQL - Nested query optimization

How can I optimize this query SQL?
CREATE TABLE table1 AS
SELECT * FROM temp
WHERE Birth_Place IN
(SELECT c.DES_COM
FROM tableCom AS c
WHERE c.COD_PROV IS NULL)
ORDER BY Cod, Birth_Date
I think that the problem is the IN clause
First of all it's not quite valid SQL, since you are selecting and sorting by columns that are not part of the group. What you want to do is called "select top N in group", check out Select first row in each GROUP BY group?
Your query doesn't make sense, because you have SELECT * with GROUP BY. Ignoring that, I would recommend writing the query as:
SELECT t.*
FROM temp t
WHERE EXISTS (SELECT 1
FROM tableCom c
WHERE t.Birth_Place = c.DES_COM AND
c.COD_PROV IS NULL
)
ORDER BY Cod, Birth_Date;
For this, I recommend an index on tableCom(desc_com, cod_prov). Your database might also be able to use an an index on temp(cod, birth_date, birthplace).

SQL: How to decrease the statement execution time?

I'm not an expert in SQL, i have an sql statement :
SELECT * FROM articles WHERE article_id IN
(SELECT distinct(content_id) FROM contents_by_cats WHERE cat_id='$cat')
AND permission='true' AND date <= '$now_date_time' ORDER BY date DESC;
Table contents_by_cats has 11000 rows.
Table articles has 2700 rows.
Variables $now_date_time and $cat are php variables.
This query takes about 10 seconds to return the values (i think because it has nested SELECT statements) , and 10 seconds is a big amount of time.
How can i achieve this in another way ? (Views or JOIN) ?
I think JOIN will help me here but i don't know how to use it properly for the SQL statement that i mentioned.
Thanks in advance.
A JOIN is exactly what you are looking for. Try something like this:
SELECT DISTINCT articles.*
FROM articles
JOIN contents_by_cats ON articles.article_id = contents_by_cats.content_id
WHERE contents_by_cats.cat_id='$cat'
AND articles.permission='true'
AND articles.date <= '$now_date_time'
ORDER BY date DESC;
If your query is still not as fast as you would like then check that you have an index on articles.article_id and contents_by_cats.content_id and contents_by_cats.cat_id. Depending on the data you may want an index on articles.date as well.
Do note that if the $cat and $now_date_time values are coming from a user then you should really be preparing and binding the query rather than just dumping these values into the query.
This is the query we are starting with:
SELECT a.*
FROM articles a
WHERE article_id IN (SELECT distinct(content_id)
FROM contents_by_cats
WHERE cat_id ='$cat'
) AND
permission ='true' AND
date <= '$now_date_time'
ORDER BY date DESC;
Two things will help this query. The first is to rewrite it using exists rather than in and to simplify the subquery:
SELECT a.*
FROM articles a
WHERE EXISTS (SELECT 1
FROM contents_by_cats cbc
WHERE cbc.content_id = a.article_id and cat_id = '$cat'
) AND
permission ='true' AND
date <= '$now_date_time'
ORDER BY date DESC;
Second, you want indexes on both articles and contents_by_cats:
create index idx_articles_3 on articles(permission, date, article_id);
create index idx_contents_by_cats_2 on contents_by_cat(content_id, cat_id);
By the way, instead of $now_date_time, you can just use the now() function in MySQL.

remove duplicate rows in SQL Server Query

how could we remove or not displaying duplicate row with some conditional clause in sqlserver query, the case look like this one,
code decs
-------------------------
G-006 New
G-006 Re-Registration
how can we display just G-006 with Re-Registration Desc, i have tried with this query but no luck either
with x as (
select new_registration_no,category,rn = row_number()
over(PARTITION BY new_registration_no order by new_registration_no)
from equipment_registrations
)
select * from x
By using the same field in the PARTITION BY and ORDER BY clause, the rn field will always equal 1.
Assuming that new_registration_no = code and category = decs, you could change the ORDER BY field to be ORDER BY category DESC to get that result. However, that's a pretty arbitrary ORDER BY - you're just basing it on a random text value. I'm also not 100% sure how well the ROW_NUMBER() function works in a CTE.
A better solution might be something like:
SELECT *
FROM
(
SELECT
New_Registration_No,
Category,
ROW_NUMBER() OVER
(
PARTITION BY New_Registration_No
ORDER BY
CASE
WHEN Category = 'Re-Registration' THEN 1
WHEN Category = 'New' THEN 2
ELSE 3
END ASC ) rn
FROM Equipment_Registrations
) s
WHERE rn = 1
You can set the order in the CASE statement to be whatever you want - I'm afraid that without more information, that's the best solution I can offer you. If you have a known list of values that might appear in that field, it should be easy; if not, it will be a little harder to configure, but that will be based on business rules that you did not include in your original post.

Why does MySQL query not return newest row

I got specific query:
SELECT *
FROM stats
WHERE mod_name = 'module'
GROUP BY domain
ORDER BY addition_date DESC
I want to retrive, the newest value for every domain. I know there is a domain x.com value with date 2014-02-19.
However, this query returns me row with date: 2014-01-06
That's quite simple query... why it does not take group by domains and take only newest value?
Am I missing something?
The order by takes place after the group by. That is why your query does not work. Here is a way to get what you want:
SELECT s.*
FROM stats s
WHERE mod_name = 'module' and
not exists (select 1
from stats s2
where s2.mod_name = s.mod_name and
s2.addition_date > s.addition_date
)
ORDER BY addition_date DESC;
To get the best performance, create an index on stats(mod_name, addition_date).

Get count of complex query

I would like to count the total number of rows returned by the following query:
SELECT table1.*, COUNT(table2.fk) * (100/18) AS 'number'
FROM table1 INNER JOIN table2 ON table1.pk = table2.fk
WHERE table1.Street LIKE '$Street%'
AND table1.City LIKE '$City%'
AND table1.Zip LIKE '%$Zip'
AND table1.DOBY LIKE '%$DOBY'
AND table1.DOBM LIKE '%$DOBM'
AND table1.DOBD LIKE '%$DOBD'
AND table1.Gender LIKE '$gender%'
AND table2.year>= 2004
AND table2.type IN ('AA', 'AB', 'AC')
GROUP BY table2.fk
HAVING (COUNT(table2.fk) * (100/18)) >= '$activity'
ORDER BY DOBY, DOBM, DOBD ASC
The query counts the number or times the primary key of table1 occurs as the foreign key of table2, and calculates a percentage ('number') based on a fixed amount. It works well enough, but I'm having trouble getting the total amount of records found for my pagination script.
I would appreciate it if anyone can offer some suggestions or solutions.
u can do SQL_CALC_FOUND_ROWS (google for exact syntax)
And then use SELECT FOUND_ROWS() AS total
Going with what Itay Moav says, a programming language should have a function for the found_rows function. As per the function documentation, it returns the number of rows of a SELECT statement with a LIMIT keyword if the LIMIT keyword wasn't there.
If it doesn't, you can just make another SELECT query to the database: SELECT FOUND_ROWS();. It will return the same information.