I was reading the books fundamentals of database systems and in the topic nested subqueries(set comparison) it was written that some and in are identical whereas <>some and not in are not.
According to me <>some means "not at least one" and not in means "not in the set"...so I think they should mean the same.
They are not the same!
<>SOME means: not = a or not = b or not = c...
NOT IN means: not = a and not = b and not = c...
Hope this will be more clear for you now.
For example:
SELECT CustomerID
FROM Sales.Customer
WHERE TerritoryID <> ANY
(SELECT TerritoryID
FROM Sales.SalesPerson);
This query return every single CustomerID with the exception of those for wich the TerritoryID is NULL.
While if you use NOT IN the query will return nothing.
<> only apply to 1 value, while "not in" apply to 1 or more values, e.g.
1. WHERE id <> '123'
2. WHERE id NOT IN ('123') --same as case 1
3. WHERE id NOT IN ('123', '456')
Related
Is it possible to use CASE statement in WHERE condition like below?
SELECT act.id_activity FROM activity act
LEFT JOIN work w ON w.id_work = act.id_work
WHERE
w.work_type=1
AND w.work_tender in (1,2)
AND act.id_activity_type IN
(CASE WHEN w.work_tender=1 THEN '2,3' WHEN w.work_tender=2 THEN '2,3,4,9' END)
it returns no error but the results always display act.id_activity_type = 2 instead of 2,3 or 2,3,4,9
In this case 1 work (table work) can have many activities (table activity). i want to display activities based on work.work_tender type. if work.work_tender=1 then need to choose activity.id_activity_type IN (2,3). if work.work_tender=2 then need to choose activity.id_activity_type IN (2,3,4,9)
You can try to write correct logic by OR & AND.
SELECT act.id_activity FROM activity act
LEFT JOIN work w ON w.id_work = act.id_work
WHERE
w.work_type=1
AND (
(act.id_activity_type IN ('2','3') AND w.work_tender=1) OR
(act.id_activity_type IN ('2','3','4','9') AND w.work_tender=2)
)
I think case is used for that case. I think it is possible to use in that case. And also for orderby phrase.
Maybe you can try with this:
SELECT *
FROM activity a
JOIN work w
ON w.work_tender=
CASE WHEN a.id_activity_type IN (2,3) THEN 1
WHEN a.id_activity_type IN (2,3,4,9) THEN 2 END;
I'm using CASE expression here to assign value matching w.work_tender if the a.id_activity_type fit the condition. So, if a.id_activity_type IN (2,3) THEN 1 will match with w.work_tender=1 similarly with a.id_activity_type IN (2,3,4,9) THEN 2 will match with w.work_tender=2.
Demo fiddle
I have 3 tables in my DB; Transactions, transaction_details, and accounts - basically as below.
transactions :
id
details
by_user
created_at
trans_details :
id
trans_id (foreign key)
account_id
account_type (Enum -[c,d])
amount
Accounts :
id
sub_name
In each transaction each account may be creditor or debtor. What I'm trying to get is an account statement (ex : bank account movements) so I need to query each movement when the account is type = c (creditor) or the account type is = d (debtor)
trans_id, amount, created_at, creditor_account, debtor_account
Update : I tried the following query but i get the debtor column values all Null!
SELECT transactions.created_at,trans_details.amount,(case WHEN trans_details.type = 'c' THEN sub_account.sub_name END) as creditor,
(case WHEN trans_details.type = 'd' THEN sub_account.sub_name END) as debtor from transactions
JOIN trans_details on transactions.id = trans_details.trans_id
JOIN sub_account on trans_details.account_id = sub_account.id
GROUP by transactions.id
After the help of #Jalos I had to convert the query to Laravel which also toke me 2 more hours to convert and get the correct result :) below is the Laravel code in case some one needs to perform such query
I also added between 2 dates functionality
public function accountStatement($from_date,$to_date)
{
$statemnt = DB::table('transactions')
->Join('trans_details as credit_d',function($join) {
$join->on('credit_d.trans_id','=','transactions.id');
$join->where('credit_d.type','c');
})
->Join('sub_account as credit_a','credit_a.id','=','credit_d.account_id')
->Join('trans_details as debt_d',function($join) {
$join->on('debt_d.trans_id','=','transactions.id');
$join->where('debt_d.type','d');
})
->Join('sub_account as debt_a','debt_a.id','=','debt_d.account_id')
->whereBetween('transactions.created_at',[$from_date,$to_date])
->select('transactions.id','credit_d.amount','transactions.created_at','credit_a.sub_name as creditor','debt_a.sub_name as debtor')
->get();
return response()->json(['status_code'=>2000,'data'=>$statemnt , 'message'=>''],200);
}
Your transactions table denotes transaction records, while your accounts table denotes account records. Your trans_details table denotes links between transactions and accounts. So, since in a transaction there is a creditor and a debtor, I assume that trans_details has exactly two records for each transaction:
select transactions.id, creditor_details.amount, transactions.created_at, creditor.sub_name, debtor.sub_name
from transactions
join trans_details creditor_details
on transactions.id = creditor_details.trans_id and creditor_details.account_type = 'c'
join accounts creditor
on creditor_details.account_id = creditor.id
join trans_details debtor_details
on transactions.id = debtor_details.trans_id and debtor_details.account_type = 'd'
join accounts debtor
on debtor_details.account_id = debtor.id;
EDIT
As promised, I am looking into the query you have written. It looks like this:
SELECT transactions.id,trans_details.amount,(case WHEN trans_details.type = 'c' THEN account.name END) as creditor,
(case WHEN trans_details.type = 'd' THEN account.name END) as debtor from transactions
JOIN trans_details on transactions.id = trans_details.trans_id
JOIN account on trans_details.account_id = account.id
GROUP by transactions.id
and it is almost correct. The problem is that due to the group-by MySQL can only show a single value for each record for creditor and debtor. However, we know that there are exactly two values for both: there is a null value for creditor when you match with debtor and a proper creditor value when you match with creditor. The case for debtor is similar. My expectation for this query would have been that MySQL would throw an error because you did not group by these computed case-when fields, yet, there are several values, but it seems MySQL can surprise me after so many years :)
From the result we see that MySQL probably found the first value and used that both for creditor and debtor. Since it met with a creditor match as a first match, it had a proper creditor value and a null debtor value. However, if you write bullet-proof code, you will never meet these strange behavior. In our case, doing some minimalistic improvements on your code transforms it into a bullet-proof version of it and provides correct results:
SELECT transactions.id,trans_details.amount,max((case WHEN trans_details.type = 'c' THEN account.name END)) as creditor,
max((case WHEN trans_details.type = 'd' THEN account.name END)) as debtor from transactions
JOIN trans_details on transactions.id = trans_details.trans_id
JOIN account on trans_details.account_id = account.id
group by transactions.id
Note, that the only change I did with your code is to wrap a max() function call around the case-when definitions, so we avoid the null values, so your approach was VERY close to a bullet-proof solution.
Fiddle: http://sqlfiddle.com/#!9/d468dc/10/0
However, even though your thought process was theoretically correct (theoretically there is no difference between theory and practice, but in practice they are usually different) and some slight changes are transforming it into a well-working code, I still prefer my query, because it avoids group by clauses, which can be useful, if necessary, but here it's unnecessary to do group by, which is probably better in terms of performance, memory usage, it's easier to read and keeps more options open for you for your future customisations. Yet, your try was very close to a solution.
As about my query, the trick I used was to do several joins with the same tables, aliasing them and from that point differentiating them as if they were different tables. This is a very useful trick that you will need a lot in the future.
let's say I have 4 tables
The requirements are:
If a supplier accepted an order then in the orders_suppliers table the order_supplier_status_id change to 3 .
If all suplliers associated to a specific combined order accepted their orders then in the Combined_orders table
the Combined_order_status_id change to 3.
If at least one supplier accepted an order and all order are not accepted than in the table Combined_orders the
Combined_order_status_id change to 2.
My question is: Is it possible in one query to update the Combined_order_status_id to accepted only if all suppliers accepted their orders ?
something like:
update Combined_orders
set Combined_orders.Combined_order_status_id = 3 if(all orders_suppliers.order_supplier_status_id == 3 )
otherwise
set Combined_orders.Combined_order_status_id = 2
where orders_suppliers.Combined_order_id = Combined_orders.Combined_order_id
Each time a supplier accept an order , I would like to execute this query.
For now I didn't find a way to do that in only one query. It is reaaly important for me to do that in one query , because from what I understand if is made in one query it would be an atomic operation.
You can use join and an aggregation:
update Combined_orders co join
(select os.combined_order_id, min(os.order_supplier_status_id) as min_ossi,
max(os.order_supplier_status_id) as max_ossi
from orders_suppliers os
group by os.combined_order_id
) os
on os.combined_order_id = co.combined_order_id
set co.Combined_order_status_id = (case when min_ossi = max_ossi and min_ossi = 3 then 3 else 2 end);
i have the follwoing query:
SELECT COALESCE(income_adsense, income_adsense_u) AS "REV",
CASE COALESCE(income_adsense, income_adsense_u)
WHEN income_adsense THEN "REAL"
WHEN income_adsense_u THEN "USER"
END AS source
FROM revenue_report LIMIT 1;
which will return answer like this:
REV | source
376 | REAL
now the query works fine but the problem is i want to execute this select couple of times for different entity (adsense in the example).
the best i could get is this:
SELECT rr.site_id, ws.website_name,
CASE COALESCE(income_adsense, income_adsense_u)
WHEN income_adsense THEN "REAL"
WHEN income_adsense_u THEN "USER"
END AS adsense_source,
CASE COALESCE(income_taboola, income_taboola_u)
WHEN income_taboola THEN "REAL"
WHEN income_taboola_u THEN "USER"
END AS taboola_source
FROM revenue_report rr
INNER JOIN websites ws ON ws.website_id = rr.site_id
WHERE (data_date BETWEEN '2017-03-18' AND '2017-03-18')
GROUP BY site_id
LIMIT 1
but the problem here is i'm missing the "REV" value from the upper example. I know it doesn't exists in the second query, but this is the last working attempt. any idea how can i add the "REV" value logic to the second query?
in the second query i will get this structure of result:
site_id|website_name|adsense_source|taboola_source
but here im missing the COALESCE result from the first query which in the example was 376
Well why can't you just include it in your SELECT list like
SELECT rr.site_id, ws.website_name,
COALESCE(income_adsense, income_adsense_u) AS "REV", //Here
CASE COALESCE(income_adsense, income_adsense_u)
WHEN income_adsense THEN "REAL"
WHEN income_adsense_u THEN "USER"
END AS adsense_source,
CASE COALESCE(income_gol, income_gol_u)
WHEN income_taboola THEN "REAL"
WHEN income_taboola_u THEN "USER"
END AS taboola_source
FROM revenue_report rr
INNER JOIN websites ws ON ws.website_id = rr.site_id
WHERE (data_date BETWEEN '2017-03-18' AND '2017-03-18')
GROUP BY site_id
LIMIT 1
I have a MySQL query that includes <> in it. I don't know the exact usage of it.
SELECT * FROM table_laef WHERE id = ? AND genre_type <> 'LIVE'
P.S.: Im sorry for this basic syntax, since I have searched for this on Google. All they give is about <=>. Thanks anyway, guys!
<> is Standard SQL and stands for not equal or !=.
<> means not equal to, != also means not equal to.
Documentation
<> means NOT EQUAL TO, != also means NOT EQUAL TO. It's just another syntactic sugar. both <> and != are same.
The below two examples are doing the same thing. Query publisher table to bring results which are NOT EQUAL TO <> != USA.
SELECT pub_name,country,pub_city,estd FROM publisher WHERE country <> "USA";
SELECT pub_name,country,pub_city,estd FROM publisher WHERE country != "USA";
In MySQL, I use <> to preferentially place specific rows at the front of a sort request.
For instance, under the column topic, I have the classifications of 'Chair', 'Metabolomics', 'Proteomics', and 'Endocrine'. I always want to list any individual(s) with the topic 'Chair', first, and then list the other members in alphabetical order based on their topic and then their name_last.
I do this with:
SELECT scicom_list ORDER BY topic <> 'Chair',topic,name_last;
This outputs the rows in the order of:
Chair
Endocrine
Metabolomics
Proteomics
Notice that topic <> 'Chair' is used to select all the rows with 'Chair' first. It then sorts the rows where topic = Chair by name_last.*
*This is a bit counterintuitive since <> equals != based on other feedback in this post.
This syntax can also be used to prioritize multiple categories. For instance, if I want to have "Chair" and then "Vice Chair" listed before the rest of the topics, I use the following
SELECT scicom_list ORDER BY topic <> 'Chair',topic <> 'Vice Chair',topic,name_last;
This outputs the rows in the order of:
Chair
Vice Chair
Endocrine
Metabolomics
Proteomics
In MySQL, <> means Not Equal To, just like !=.
mysql> SELECT '.01' <> '0.01';
-> 1
mysql> SELECT .01 <> '0.01';
-> 0
mysql> SELECT 'zapp' <> 'zappp';
-> 1
see the docs for more info
<> is equal to != i.e, both are used to represent the NOT EQUAL operation. For instance, email <> '' and email != '' are same.
I know im late to the game but maybe this will help somebody...
this is not true even though everyone wrote it
<> is equal to !=
it actually is less than or greater than
the exception is with NULL
column <> 3 will not get null columns
column != 3 will get null columns
hope it helps