Query with two NOT IN subqueries - mysql

Is it possible to have a query with two NOT IN on two subqueries:
SELECT u.feedbackid
FROM user_feedback u
WHERE u.feedbackid NOT IN ( SELECT feedbackid
FROM user_feedback_sent)
AND NOT IN (SELECT feedbackid
FROM user_feedback_received)
The query throws an error on the second NOT IN saying incorrect syntax.

You're missing the column name which shuold NOT be in the second subquery. This will probably works as you need:
SELECT u.feedbackid
FROM user_feedback u
WHERE u.feedbackid NOT IN (SELECT a.feedbackid
FROM user_feedback_sent a)
AND u.feedbackid NOT IN (SELECT b.feedbackid
FROM user_feedback_received b)
Identation its always a good practice to implement when writing SQL code.
Hope it helps

Related

Alternatives to using "having" clause for alias fields

I have this somewhat complex sql query that works ok without the final where clause. I'm looking to filter some records using the column unreviewed_records which is an alias
Problem is that I get an error saying unreviewed_records cannot be found. I found some information saying that alias fields are not permitted to be used in where clauses and I'm not sure what's the best way to fix this. Considered using a computed column but I'm not sure how that works yet and I'm hoping there's an easier fix to the query.
Also I find that switching to using the "having" clause work for aliases, but I'll only resort to this if there's no better alternative, to avoid the performance hit.
Any pointers would be helpful :)
select
r_alias.serv_id, r_alias.node_id,
SUM(g_alias.total_records)- SUM(r_alias.reviewed_records) AS unreviewed_records,
SUM(r_alias.reviewed_records) AS reviewed_records,
SUM(g_alias.total_records) AS total_records,
FROM (
SELECT prs.serv_id,
prs.node_id,
SUM(prs.reviewed_records) AS reviewed_records,
FROM p_rev_server prs
WHERE
prs.area_id = 3
AND prs.subId = 3
AND prs.sId = 12
GROUP BY prs.serv_id, prs.node_id, prs.domain_name
) r_alias
INNER JOIN (SELECT
serv_id,
node_id,
SUM(pgs.total_records) AS total_records,
FROM p_gen_serve pgs
WHERE pgs.area_id = 3
AND pgs.subId = 3
AND pgs.sId = 12
AND pgs.total_records > 0
GROUP BY pgs.serv_id, pgs.node_id, pgs.domain_name
) g_alias
ON g_alias.serv_id = r_alias.serv_id AND g_alias.node_id = r_alias.node_id
LEFT JOIN p_cust_columns cust_cols
ON cust_cols.node_id = r_alias.node_id AND cust_cols.serv_id = r_alias.serv_id
where (((NOT (unreviewed_records IS NULL)) AND (unreviewed_records = 5)))
group by r_alias.serv_id, r_alias.node_id
order by g_alias.node_id ASC
limit 25
The reason aliases are not allowed in a WHERE clause is that the expressions in the SELECT list are not evaluated until after the rows are filtered by the WHERE clause. So it's a chicken-and-egg problem.
The easiest and most common alternative is a derived table:
SELECT a, b, c
FROM (
SELECT a, b, a+b AS c
FROM mytable
WHERE b = 1234
) AS t
WHERE c = 42;
This example shows that you can put some filtering conditions inside the derived table subquery, so you can at least reduce the result set partially, before the result of the subquery is turned into a temporary table.
Then in the outer query, you can reference a column that was derived from an expression in the select-list of the subquery. In this example, it's the c column.
The CTE approach is basically the same, it creates a temporary table to store the result of the inner query (the CTE), and then you can apply conditions to that in the outer query.
WITH t AS (
SELECT a, b, a+b AS c
FROM mytable
WHERE b = 1234
)
SELECT a, b, c
FROM t
WHERE c = 42;
The CTE solution is not better than the derived-table approach, unless you need to reference the CTE multiple times in the outer query, i.e. doing a self-join.
Yeah, you are kind of SOL, WHERE can't know what an alias will be. So, frankly, a CTE, common table expression, is probably your best bet here. It should work, though not all RDBMS really support them (MySQL for example only in version 8).

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).

Set a list in a variable in subquery - MYSQL

My problem is the following, I want set a list of ID in a variable, then use this variable in a subquery. The problem is that WorkBench (my GUI) return the following error : "subquery returning multiple rows". It seems to me that's what I want.
Please explain me where I am wrong.
This is my query :
set #listID := (select ID_VOIE as ID from voies
where ORIGINE = 'XXX'
group by CODE_INSEE, CODE_VOIE
having count(*) > 1);
select substring(v.CODE_INSEE,1,2), count(*) from voies v
where v.ID_VOIE in (#listID)
group by substring(vs.CODE_INSEE,1,2);
The thing is I'm blocked with the "group by", I want do a groupd by after a first group by, that's why I can't (or at least i didn't find a way) write the request with a single WHERE clause.
The thing is I know that I can put the whole request directly in my subquery instead of using variable but :
It can let me use this trick in another requests that needed this behaviour (DRY concept !)
I'm not sure but the subquery will be executed in each turn of my loop, and that will be very inefficient
So I seek 2 possible ways : a way that let me use a list in a variable in a subquery OR a way that let me use "group by" twice in a single query.
Thanks you in advance for your answers (oh and sorry for my english, this is not my maternal language).
Unless you need that variable for something else, you should be able to skip it entirely as follows:
SELECT
SUBSTRING(v.CODE_INSEE,1,2),
COUNT(*)
FROM
voies v
WHERE
v.ID_VOIE in
(SELECT
ID_VOIE as ID
FROM
voies
WHERE
ORIGINE = 'XXX'
GROUP BY
CODE_INSEE,
CODE_VOIE
HAVING COUNT(*) > 1)
GROUP BY
SUBSTRING(vs.CODE_INSEE,1,2);
As you say, the subquery will be executed for all rows. To avoid that, a variable would be best, but MySQL doesn't support table variables. Instead, you can use a temporary table:
IF EXISTS DROP TABLE myTempTable;
CREATE TEMPORARY TABLE myTempTable (ID_VOIE int); -- I don't know the datatype
INSERT INTO myTempTable (ID_VOIE)
SELECT DISTINCT -- using distinct so I can join instead of use IN.
ID_VOIE as ID from voies
WHERE
ORIGINE = 'XXX'
GROUP BY
CODE_INSEE, CODE_VOIE
HAVING COUNT(*) > 1
And now you can do this:
SELECT
SUBSTRING(v.CODE_INSEE,1,2), COUNT(*)
FROM
voies v
JOIN myTempTable tt ON
v.ID_VOIE = tt.ID_VOIE
GROUP BY SUBSTRING(vs.CODE_INSEE,1,2);

Unknown column in 'where-clause'

I have simple sql:
SELECT *
FROM `oc_artists`
WHERE `oc_artists`.`artist_id`=`oc_artists_tags`.`artist_id`
AND `oc_artists_tags`.`artist_tag` LIKE '%klass%'
When I run this I got:
1054 - Unknown column 'oc_artists_tags.artist_id' in 'where clause'
This is a sql for a search script. I need simple return unique results from oc_artists if query matches with oc_artists_tags.artist_tag.
You need to JOIN the table oc_artists_tags too and you can achieve this two way,
Option 1
SELECT *
FROM `oc_artists`
INNER JOIN `test2` on `oc_artists`.`artist_id`=`oc_artists_tags`.`artist_id`
AND `oc_artists_tags`.`artist_tag` LIKE '%klass%'
Option 2
SELECT *
FROM `oc_artists`,`oc_artists_tags`
WHERE `oc_artists`.`artist_id`=`oc_artists_tags`.`artist_id`
AND `oc_artists_tags`.`artist_tag` LIKE '%klass%'
2nd join table is missing from your query, so include oc_artists_tags table in your join...
Finally your query should be-
SELECT *
FROM `oc_artists`, `oc_artists_tags`
WHERE `oc_artists`.`artist_id`=`oc_artists_tags`.`artist_id`
AND `oc_artists_tags`.`artist_tag` LIKE '%klass%'
You can also use join or inner join instead of comma join-
SELECT *
FROM `oc_artists` as oa
join `oc_artists_tags` as oat on oa.artist_id=oat.artist_id
WHERE oat.artist_tag LIKE '%klass%';
To gain performance follow below points-
You should select only required columns instead of *.
join fields must be indexed and better will be that these fields should be integer type.
If possible avoid '%'in left side in like clause as it will not use index and slow your query. for example artist_tag like 'klass%' will use index but '%klass%' will not.
You have to join the other table.Join helps you.

can i use select where in(x,y,z)?

I'm a mysql beginner these days, i appreciate for your advise.
I got a problem my sql query
INSERT IGNORE INTO TB_AUTO_BAN(MEMO, REG_DATE, USER_ID, NAME, PHONE_NUM)
(
SELECT 'test' AS MEMO, NOW() AS REG_DATE, a.USER_ID, a.NAME, a.CONTACT_NUM
FROM TB_CONTACT AS a,TB_CONTACT_GROUP AS b
WHERE b.USER_ID = 'spark#naver.com'
AND b.GROUP_CONTACT_SEQ = IN(12800,12801)
AND a.GROUP_CONTACT_SEQ = b.GROUP_CONTACT_SEQ
Bold text part is the problem, how should I modify it??
Your query looks ok, except for the = in. Only in is needed.
I would write the query as:
INSERT IGNORE INTO TB_AUTO_BAN(MEMO, REG_DATE, USER_ID, NAME, PHONE_NUM)
SELECT 'test' AS MEMO, NOW() AS REG_DATE, c.USER_ID, c.NAME, c.CONTACT_NUM
FROM TB_CONTACT AS c JOIN
TB_CONTACT_GROUP AS cg
ON c.GROUP_CONTACT_SEQ = cg.GROUP_CONTACT_SEQ
WHERE cg.USER_ID= 'spark#naver.com' AND
cg.GROUP_CONTACT_SEQ IN (12800, 12801) ;
In addition to fixing the condition, this changes the table aliases to be abbreviations rather than arbitrary letters. It also uses standard join syntax instead of implicit joins with the condition buried in the where clause.
the equality sign "=" is superfluous. just delete it, and leave: b.GROUP_CONTACT_SEQ IN (12800,12801)