sql SELECT query not doing the opposite - mysql

im using a query that checks for duplicate values, but now i want it to do the opposite of this query:
SELECT * FROM orders WHERE buy_date (SELECT buy_date FROM orders GROUP BY buy_date HAVING count(*)>1)
Result:
I tried changing HAVING count(*)=0 / HAVING count(*)<1 put it returns nothing

The limiting clause having count(*) < 1 will not return values. You cannot return a recordset with half a row! Try HAVING count(*) < 2 which will return rows with a count of 1.
You may also want to check out the DISTINCT function which returns distinct values.

I suppose you consider duplicate two orders with the same buy_date and different id (I suppose id is the name of PK field)
For duplicate - try this:
SELECT o1.*
FROM orders o1
WHERE EXISTS(
SELECT 'duplicate'
FROM orders o2
WHERE o1.id <> o2.id
AND o1.buy_date = o2.buy_date
)
For single - try this:
SELECT o1.*
FROM orders o1
WHERE NOT EXISTS(
SELECT 'duplicate'
FROM orders o2
WHERE o1.id <> o2.id
AND o1.buy_date = o2.buy_date
)

Having Count > 1 returns duplicates as you said. Having Count = 1 will return non duplicates.

Shouldn't it be count(*) = 1?
If you have count(*) = 0 it means that you select only those record that do not exist... so it correctly returns nothing.
Or if you want to be mathematically correct, negation of sth>1 is sth<=1

Related

Select something from mysql database and order it by count (where)

I have a problem with selecting something from my database. Here is the sql sentence:
SELECT name
FROM table1
JOIN table2
ON table1.id=table2.advid
GROUP BY advid
ORDER BY COUNT(table2.likes) ASC
This will output name with the least table2.likes to the highest value of table2.likes
The problem is that table2.likes contain both likes and dislikes. Likes are marked with 1, and dislikes are marked with 2 in the table.
Currently, if there is...
...written in the table, the syntax will count both likes and dislikes so the result would be 6. I would need this result to be zero, which means when counting, dislikes have to be deduced from the number of likes. Which also means this part of the sentence: ORDER BY COUNT(table2.likes) ASC would have to be changed, but I don't know how.
Use conditional aggregation with SUM():
SELECT name
FROM table1 t1 JOIN
table2 t2
ON t2.id = t2.advid
GROUP BY name
ORDER BY SUM(CASE WHEN t2.likes = 1 THEN 1 ELSE -1 END) ASC;
Note: I changed the GROUP BY to be by name. The GROUP BY columns should match the columns you are selecting.
Use a case expression to count 1 for likes and -1 for dislikes. It is considered good style and less error-prone not to join and then aggregate, but to join the already aggregated data instead.
select t1.name, t2.sumlikes
from table1 t1
join
(
select advid, sum(case when likes = 1 then 1 else -1 end) as sumlikes
from table2
group by advid
) t2 on t2.advid = t1.id
order by sumlikes;
If you want to list names without like entries, too, then turn the join into a left outer join and select coalesce(t2.sumlikes, 0) instead.

How can i check for multiple values in the same variable SQL

SO basically, i want to return "cid" (customer id's) of users who has ordered a certain product "p07 & p01".
My currently query don't work, it only works when i check for one value instead of two. But i need it to check for two. The return value i get is basically an empty space. My guess is, it doesn't know which "pid" to use so it returns nothing.
SELECT cid FROM orders
WHERE pid = 'p07' AND pid = 'p01'
You can use aggregation for this purpose. No single row can have both values, so you need to look at groups of them:
SELECT cid
FROM orders
WHERE pid IN ('p07', 'p01')
GROUP BY cid
HAVING COUNT(DISTINCT pid) = 2;
If you are using Oracle database than you can use the INTERSECT keyword to get the answer. Following is the syntax for the same:
(SELECT cid FROM orders where pid = 'p07')
intersect
(SELECT cid FROM orders where pid = 'p01').
but if you are using MySQL, than this INTERSECT keyword will not work.
Following is the solution for the MySql database:
SELECT t1.cid from (
(SELECT DISTINCT cid FROM orders where pid = 'p07')
UNION ALL
(SELECT DISTINCT cid FROM orders where pid = 'p01')
) AS t1 GROUP BY cid HAVING count(*) >= 2;
If you want to use the above query in the Oracle database than there is a bit change in the syntax. Following is the syntax for the same:
SELECT t1.cid from (
(SELECT DISTINCT cid FROM orders where pid = 'p07')
UNION ALL
(SELECT DISTINCT cid FROM orders where pid = 'p01')
) t1 GROUP BY cid HAVING count(*) > = 2

Get values from a table which are not present only in the 'IN' clause

I want to get values which are not present in the table ,by considering the values only in the IN clause .
For example ,
select orderNumber from order where orderNumber in (List of orderNumbers)
This will give the orderNumbers which are present in the table by considering the values present in the IN clause , likewise I want the orderNumbers which are not present in the table by considering the values present in the IN clause .
Is there any query logic present to handle this situation?
You need a join to do this with a left outer join and a where clause:
select on.*
from (select 1 as OrderNumber from dual union all
select 2 from dual
. . .
select n from dual
) ordn left outer join
orders o
on o.ordernumber = ordn.ordernumber
where o.ordernumber is NULL;
I think what you are looking for is the MINUS keyword. This works without an IN clause though, but you should be able to make this work for your usecase.
This gives all ordernumbers in in_clause_table that are not in order.
SELECT ordernumbers FROM in_clause_table
MINUS
SELECT orderNumber FROM order;
Note: incidentally, there are many ways to achieve this, but I think this might be most concise one.
One way to do this without repeating the IN clause would be to use a subquery factoring clause:
WITH Q1 AS
(SELECT ORDERNUMBER
FROM ORDERS
WHERE ORDERNUMBER IN (1, 2, 3, 4))
SELECT q.ORDERNUMBER AS INCLUDED_ORDERNUMBER,
NULL AS EXCLUDED_ORDERNUMBER
FROM Q1 q
UNION ALL
SELECT NULL AS INCLUDED_ORDERNUMBER,
o.ORDERNUMBER AS EXCLUDED_ORDERNUMBER
FROM ORDERS o
WHERE o.ORDERNUMBER NOT IN (SELECT ORDERNUMBER FROM Q1);
Share and enjoy.

if "Subquery returns more than 1 row" consider it NULL

I'm trying to sync store ids on newtable with the ids from the maintable here:
UPDATE newtable t SET t.store_id = (SELECT store_id FROM maintable s
WHERE t.state = s.state AND s.city = t.city AND t.name = s.name)
Whenever a subquery returns more than one row it errors out with "Subquery returns more than 1 row", but when it returns zero rows the subquery is considered to have returned nothing so the store_id on newtable remains NULL. Nothing new here, it's just how it works.
I'd like to know if it's possible to let the subquery output the same as what it does when it has no matches when it has more than one matching row.
This way I'd get the store_id synced only for ONE matching row on the main table and skipped when more than one matching row comes out in the subquery.
I think you might be looking for a HAVING clause to force the query to match exactly once:
UPDATE newtable t
SET t.store_id = (
SELECT store_id
FROM maintable s
WHERE t.state = s.state
AND s.city = t.city
AND t.name = s.name
HAVING COUNT(*) = 1
)
That should make multiple matches behave the same as no matches. The HAVING clause is applied almost at the very end of the query process; if there are no matches from the WHERE or more than one match, then COUNT(*) = 1 will fail and the inner query will return nothing but if there is exactly one row then COUNT(*) = 1 will succeed and the inner query will return that single match.
You might consider putting a LIMIT 1 in your sub-query to better achieve what you are trying to accomplish, depending on your specific needs.
Otherwise, you should be able to get creative with IF or CASE:
UPDATE newtable t SET t.store_id = (
SELECT IF(num>1, NULL, storeid) FROM (
SELECT COUNT(*) AS num, storeid FROM maintable s WHERE t.state=s.state AND s.city=t.city AND t.name=s.name
)
)
Untested, but should get you in the ballpark.
UPDATE newtable t SET t.store_id = IFNULL((SELECT store_id FROM maintable s
WHERE t.state = s.state AND s.city = t.city AND t.name = s.name HAVING COUNT(*) = 1), t.store_id)
IFNULL(use_this_value_if_not_null,value_if_first_isnull)

Mysql Select within IF condition

looking to perform a query that on a particular conditions gets the data from another table.
it like
select field1, field2.... IF(fieldX=3,select value from sub_table where cat_id = 3 order by id desc limit 0,1, NULL) from abc ;
The query within the if is valid.
I am used to with implementing if conditions without any issue but those were all for some static values or a field. But, this is the first time I am trying to get a select's result in if and unable to do it.
The case is because for some particular value of 'fieldX' I need to get a record from another table.
Regards
Junaid
wrap you inner select in ( )
IF(fieldX=3, (select value from sub_table where cat_id = 3 order by id desc limit 0,1), NULL)
why not use a left join and use fieldX=3 as a join condition? if fieldX is different from 3, sql fills the field with NULL
select a.field1, a.field2, sub.value
from abc a
left join
(
select value from sub_table
where cat_id = 3
limit 0,1
) sub
on a.fieldX = 3
or, if you do want to get all rows for the corresponding values (i see you have cat_id = 3 and fieldX = 3, so basically cat_id = fieldX), just use a simple join. no need to use complicated if constructs. sql was built to do fast and efficient joins:
select a.field1, a.field2, sub.value
from abc a
left join sub_table sub
on a.fieldX = sub.cat_id
note however, that the second query will return multiple rows, when there are more matches between fieldX and cat_id (non-unique cat_id)
you could do something like:
select fields... from sub_table st
where st.idSubTable in(
Select IF(fieldX=3
,(
select st.idSubTable from sub_table where cat_id = 3 order by id desc limit 0,1
),
NULL)
from abc);
it will solve your problem.