unnecessary 1=1 in select query [duplicate] - sql

This question already has answers here:
Why would someone use WHERE 1=1 AND <conditions> in a SQL clause?
(21 answers)
Closed 2 years ago.
Below query is used in one of my product. I am not able to understand why 1=1 is mentioned. it is always going to true.
select * from emp;
select * from emp where 1=1;
As per my understanding both are same. What could be the intention of developer to put 1=1 in below query? he can simply write where condition in one of the and condition.
SELECT msi.concatenated_segments item_code,
mmt.transaction_date,
mtt.transaction_type_name,
mmt.transaction_quantity,
mcd.prior_cost,
mcd.new_cost
FROM
mtl_cst_actual_cost_details mcd,
mtl_system_items_kfv msi,
mtl_material_transactions mmt,
mtl_COST_types mtt
WHERE 1 = 1 -------------------------------------------------This I am refering
AND mcd.inventory_item_id = msi.inventory_item_id
AND mcd.organization_id = msi.organization_id
AND mcd.transaction_id = mmt.transaction_id
AND mmt.inventory_item_id = msi.inventory_item_id
AND mmt.organization_id = msi.organization_id
AND mmt.transaction_type_id = mtt.transaction_type_id
ORDER BY mcd.creation_date DESC;

where 1 = 1 is always true, so both queries are equivalent. Most databases are able to identify that when parsing the query, so there is no performance penalty involved.
A common reason why applications use this dummy where clause is that it makes it easy to further concatenate conditions in the where clause.
Starting from string 'where 1 = 1', the application can concatenate as many and predicates as necessary. Otherwise, it would need to check if a condition was already added in the query string before deciding if it is necessary to put 'and' before the condition.

If the query is generated dynamically, the logic to add the where conditions is a bit simpler if there is a first 1=1.
You can just append them like:
STATIC QUERY
AND WHERE_CONDITION_1
AND WHERE_CONDITION_2
AND WHERE_CONDITION_3
...
And they are not depending on the position.
I think some ORM systems use this approach as well.

Like I commented above – many programmers today are entirely used to "ORM's," and the sometimes-nonsensical yet grammatically-correct SQL clauses that are sometimes generated by them. And actually: "no harm, no foul."
WHERE 1=1 is of course a perfectly-valid WHERE clause if your internal logic (buried somewhere within the bowels of the ORM in question ...) was designed in such a way that you have to produce one. 🤷‍♂️
.. or, maybe, if you decide that your programming somehow needs to join(' AND ') a whole bunch of clauses, and you decide that you need to stitch a "dummy clause" in front of them. (Although, of course, you actually don't.)

Related

MS Access SQL receiving no results when joining tables in where clause

i am trying to update a colleague's MS Access application (with vb-code). I am rather experienced in writing SQL queries but i am not able to solve the following problem.
The query i am looking to fix uses a pass-through-query's result and a local MS Access table and joins them togehter in the where-clause (i tried using the normal way with ON but it seems this doesn't work when there is a pass through query involved). I have little experience with joining tables in the where-clause but is there such a thing that i cant use certain columns (of both tables) in the where-clause when joining tables in the where-clause? -> When i use a filter criteria such as columnA <> 'somerandomtext' (which is always satisfied, just to point out the problem) the query result is empty. When i delete the latter criteria in the where clause, the query returns results (although too many because i cant filter them accordingly).
Furthermore: I checked the pass-through-query, the results are correct. I checked the MS-Access table, the data in the table is correct. Therefore, i think i might be doing something wrong in the query where i join the two mentioned above.
THIS QUERY WORKS AS INTENDED AND RETURNS RESULTS:
SELECT t.tr_id, t.ser_num, t.contrgnt_id, t.pos_ekey, t.sernum AS cmdty, format(t.vol,""##,###,###.00"") AS volume, t.unit_def, t.value_date,
format(t.coup,""##,###,###.00"") AS fixprice,
format(s.calcvarprice,""##,###,###.00"") AS marketprice,
format(s.calcamount,""##,###,###.00"") AS payamount,
format(s.settlevarprice, ""##,###,##0.00"") as settleprice,
format(s.settleamount, ""##,###,##0.00"") as settleamount, s.sync
FROM pms_trans AS t, settledata AS s
WHERE t.tr_id=s.tr_id And t.is_booked='N' And t.value_date>='01.01.2021' And t.value_date<='01.04.2021'
THIS QUERY SOMEHOW RETURNS 0 RESULTS:
SELECT t.tr_id, t.ser_num, t.contrgnt_id, t.pos_ekey, t.sernum AS cmdty, format(t.vol,""##,###,###.00"") AS volume, t.unit_def, t.value_date,
format(t.coup,""##,###,###.00"") AS fixprice,
format(s.calcvarprice,""##,###,###.00"") AS marketprice,
format(s.calcamount,""##,###,###.00"") AS payamount,
format(s.settlevarprice, ""##,###,##0.00"") as settleprice,
format(s.settleamount, ""##,###,##0.00"") as settleamount, s.sync
FROM pms_trans AS t, settledata AS s
WHERE t.tr_id=s.tr_id And t.is_booked='N' And t.pos_ekey <> 'BGGS' And t.value_date>='01.01.2021' And t.value_date<='01.04.2021'
As mentioned before, i suspect that there are some limitations when joining via where-clause (although i didnt find sufficient information online).
Best Regards and thank you in advance,
Peter
First, apply the correct syntax for the date expressions:
WHERE t.tr_id=s.tr_id And t.is_booked='N' And t.pos_ekey <> 'BGGS' And t.value_date >= #2021-01-01# And t.value_date <= #2021-04-01#
Next, double-check the values for pos_ekey. For example, try to apply the filter, <> 'BGGS', directly on the field in table view.

SQLite alias (AS) not working in the same query

I'm stuck in an (apparently) extremely trivial task that I can't make work , and I really feel no chance than to ask for advice.
I used to deal with PHP/MySQL more than 10 years ago and I might be quite rusty now that I'm dealing with an SQLite DB using Qt5.
Basically I'm selecting some records while wanting to make some math operations on the fetched columns. I recall (and re-read some documentation and examples) that the keyword "AS" is going to conveniently rename (alias) a value.
So for example I have this query, where "X" is an integer number that I render into this big Qt string before executing it with a QSqlQuery. This query lets me select all the electronic components used in a Project and calculate how many of them to order (rounding to the nearest multiple of 5) and the total price per component.
SELECT Inventory.id, UsedItems.pid, UsedItems.RefDes, Inventory.name, Inventory.category,
Inventory.type, Inventory.package, Inventory.value, Inventory.manufacturer,
Inventory.price, UsedItems.qty_used as used_qty,
UsedItems.qty_used*X AS To_Order,
ROUND((UsedItems.qty_used*X/5)+0.5)*5*CAST((X > 0) AS INT) AS Nearest5,
Inventory.price*Nearest5 AS TotPrice
FROM Inventory
LEFT JOIN UsedItems ON Inventory.id=UsedItems.cid
WHERE UsedItems.pid='1'
ORDER BY RefDes, value ASC
So, for example, I aliased UsedItems.qty_used as used_qty. At first I tried to use it in the next field, multiplying it by X, writing "used_qty*X AS To_Order" ... Query failed. Well, no worries, I had just put the original tab.field name and it worked.
Going further, I have a complex calculation and I want to use its result on the next field, but the same issue popped out: if I alias "ROUND(...)" AS Nearest5, and then try to use this value by multiplying it in the next field, the query will fail.
Please note: the query WORKS, but ONLY if I don't use aliases in the following fields, namely if I don't use the alias Nearest5 in the TotPrice field. I just want to avoid re-writing the whole ROUND(...) thing for the TotPrice field.
What am I missing/doing wrong? Either SQLite does not support aliases on the same query or I am using a wrong syntax and I am just too stuck/confused to see the mistake (which I'm sure it has to be really stupid).
Column aliases defined in a SELECT cannot be used:
For other expressions in the same SELECT.
For filtering in the WHERE.
For conditions in the FROM clause.
Many databases also restrict their use in GROUP BY and HAVING.
All databases support them in ORDER BY.
This is how SQL works. The issue is two things:
The logic order of processing clauses in the query (i.e. how they are compiled). This affects the scoping of parameters.
The order of processing expressions in the SELECT. This is indeterminate. There is no requirement for the ordering of parameters.
For a simple example, what should x refer to in this example?
select x as a, y as x
from t
where x = 2;
By not allowing duplicates, SQL engines do not have to make a choice. The value is always t.x.
You can try with nested queries.
A SELECT query can be nested in another SELECT query within the FROM clause;
multiple queries can be nested, for example by following the following pattern:
SELECT *,[your last Expression] AS LastExp From (SELECT *,[your Middle Expression] AS MidExp FROM (SELECT *,[your first Expression] AS FirstExp FROM yourTables));
Obviously, respecting the order that the expressions of the innermost select query can be used by subsequent select queries:
the first expressions can be used by all other queries, but the other intermediate expressions can only be used by queries that are further upstream.
For your case, your query may be:
SELECT *, PRC*Nearest5 AS TotPrice FROM (SELECT *, ROUND((UsedItems.qty_used*X/5)+0.5)*5*CAST((X > 0) AS INT) AS Nearest5 FROM (SELECT Inventory.id, UsedItems.pid, UsedItems.RefDes, Inventory.name, Inventory.category, Inventory.type, Inventory.package, Inventory.value, Inventory.manufacturer, Inventory.price AS PRC, UsedItems.qty_used*X AS To_Order FROM Inventory LEFT JOIN UsedItems ON Inventory.id=UsedItems.cid WHERE UsedItems.pid='1' ORDER BY RefDes, value ASC))

LINQ to SQL - When do I need to Select and when can I omit the Select?

I've been playing around with LINQ to SQL and I just have a couple of simple questions:
When do I need Select on the end of my query?
When can I omit the Select?
Here are my example queries:
Dim pageRoute = From r In db.PageRoutes Where r.PageId = pageId Order By r.Id Descending
Dim pageRoute = From r In db.PageRoutes Where r.PageId = pageId Order By r.Id Descending
Dim dp = From r In db.DownloadPageOnlineOnlies Where r.PageId = pageId Order By r.Weight Descending, r.Id Ascending
Dim download = (From r In db.Downloads Where r.Id = id).First
Are any of them technically wrong?
Could they be improved with a Select or something else?
In a nutshell, I don't understand when I would need either:
Select r
Select r.AColumnINeed, r.BColumnINeed (does this improve performance?)
Thanks.
P.S. I like to write my LINQ queries on one line unless they are really big.
The select portion of the linq statement is completely optional if and only if you want to get a full object out of the collection that matches your where clause. If you want individual value(s) from an object in the collection being LINQ'd through then you need to use a select clause.
I personally always put the select r clause on the end just out of pure habit but I have come across a few issues with other peoples code when I have option strict on and they did not when they wrote the LINQ. Leaving the select clause off yields multiple late binding errors if you decide to turn option strict on in the future for whatever reason.
so in short you don't need the select clause but you are only helping yourself later on down the line if you decide to turn option strict on. And it does make your code much more readable in my opinion.
Let's have a table with 20 columns. Take a query WITH select (2 columns) and one WITHOUT. The execution plan of the two can be different and there's much less data to transfer from the database server in the former case.
it a good practice to use select plus if you have a query that requests a more precise result and like you only want a or a and b from you query you might use select and it saves the memory allocation for your query since it know exact number of variables you are going to return.

Is there a way to use the condition of an If statement as its value?

This could be a simple question, but it's one I've never seen answered before. Is there a way to use an if statement's condition as its value? This would be really useful in cases where lots of calculation is done to determine if a certain condition is met and if it is, that calculation is the result.
As an example:
if ( [intense calculation] > 0, [same intense calculation], 0)
I'm interested particularly with regards to SQL, as I'm working on a report in Access right now and so can't store the result of the intense calculation in a variable.
Not sure if such a concept exists in the MS Access report world, but how about:
MAX([intense calculation], 0)
The obvious benefit of such an approach is that the calculation would only need to be done once.
One approach in most forms of SQL would be to move the main query to a sub-query, with the intense calculation column aliased and tested in the new outer query - like so:
select v.*,
case intense_calc > 0 then intense_calc else 0 end as positive_calc
from (select [intense calculation] as intense_calc,
[other columns]
from ...) as v

Slow Query - Help with Optimization

Hey guys. This is a follow-on from this question:
After getting the right data and making some tweaks based on requests from business, I've now got this mini-beast on my hands. This query should return the total number of new jobseeker registrations and the number of new uploaded CV's:
SELECT COUNT(j.jobseeker_id) as new_registrations,
(
SELECT
COUNT(c.cv_id)
FROM
tb_cv as c, tb_jobseeker, tb_industry
WHERE
UNIX_TIMESTAMP(c.created_at) >= '1241125200'
AND
UNIX_TIMESTAMP(c.created_at) <= '1243717200'
AND
tb_jobseeker.industry_id = tb_industry.industry_id
)
AS uploaded_cvs
FROM
tb_jobseeker as j, tb_industry as i
WHERE
j.created_at BETWEEN '2009-05-01' AND '2009-05-31'
AND
i.industry_id = j.industry_id
GROUP BY i.description, MONTH(j.created_at)
Notes:
- The two values in the UNIX TIMESTAMP functions are passed in as parameters from the report module in our backend.
Every time I run it, MySQL chokes and lingers silently into the ether of the Interweb.
Help is appreciated.
Update: Hey guys. Thanks a lot for all the thoughtful and helpful comments. I'm only 2 weeks into my role here, so I'm still learning the schema. So, this query is somewhere between a thumbsuck and an educated guess. Will start to answer all your questions now.
tb_cv is not connected to the other tables in the sub-query. I guess this is the root cause for the slow query. It causes generation of a Cartesian product, yielding a lot more rows than you probably need.
Other than that I'd say you need indexes on tb_jobseeker.created_at, tb_cv.created_at and tb_industry.industry_id, and you might want to get rid of the UNIX_TIMESTAMP() calls in the sub-query since they prevent use of an index. Use BETWEEN and the actual field values instead.
Here is my attempt at understanding your query and writing a better version. I guess you want to get the count of new jobseeker registrations and new uploaded CVs per month per industry:
SELECT
i.industry_id,
i.description,
MONTH(j.created_at) AS month_created,
YEAR(j.created_at) AS year_created,
COUNT(DISTINCT j.jobseeker_id) AS new_registrations,
COUNT(cv.cv_id) AS uploaded_cvs
FROM
tb_cv AS cv
INNER JOIN tb_jobseeker AS j ON j.jobseeker_id = cv.jobseeker_id
INNER JOIN tb_industry AS i ON i.industry_id = j.industry_id
WHERE
j.created_at BETWEEN '2009-05-01' AND '2009-05-31'
AND cv.created_at BETWEEN '2009-05-01' AND '2009-05-31'
GROUP BY
i.industry_id,
i.description,
MONTH(j.created_at),
YEAR(j.created_at)
A few things I noticed while writing the query:
you GROUP BY values you don't output in the end. Why? (I've added the grouped field to the output list.)
you JOIN three tables in the sub-query while only ever using values from one of them. Why? I don't see what it would be good for, other than filtering out CV records that don't have a jobseeker or an industry attached — which I find hard to imagine. (I've removed the entire sub-query and used a simple COUNT instead.)
Your sub-query returns the same value every time. Did you maybe mean to correlate it in some way, to the industry maybe?.
The sub-query runs once for every record in a grouped query without being wrapped in an aggregate function.
First and foremost it may be worth moving the 'UNIX_TIMESTAMP' conversions to the other side of the equation (that is, perform a reverse function on the literal timestamp values at the other side of the >= and <=). That'll avoid the inner query having to perform the conversions for every record, rather than once for the query.
Also, why does the uploaded_cvs query not have any where clause linking it to the outer query? Am I missing something here?