I am honestly having trouble articulating this question to my co-workers, so please go easy on me. I can elaborate if needed.
So here is the deal, I have a theoretical question about SQL's Case When statement. This isn't a specific situation that I need help with, it is just a complex question I need answered about the abilities of the T-SQL language, which I want to know for my own future purposes.
I know that in Java you can creat loops and use the .hasNext() method to continuosly retrieve input from a source (the keyboard for example), and by doing this you can essentially create a loop that does [some action] until you run out of input.
I would like to know if I can use a similar sort of function (correct me if function is not the right terminology) that I can use along with a Case When statement in T-SQL.
Here is some psuedo code for example:
case when [Column Y has next] then 'X'
Essentially I want to know if I can tell a Case When funciton to execute continuosly until it runs out of values or encounters a null value.
Please let me know if I am on the right track here, my brain is kind of stuck somewhere between the object oriented world of Java and the relational DB world of SQL. All feedback is appreciated.
Case-When is basically a row operation. Specifically, you need to think about the set of data you are working with based on joins and where clauses, and then think about the case-when operator running against each row in the result set. Because of this, there is no concept of previous row, next row or "has next".
That being said, there's always a way to accomplish what you want. Generically speaking, I would usually recommend a "self join". This is really just a special case of a regular type of join (inner, left, right, full and cross). The difference here is that instead of joining two different tables, you join the same table back to itself. If you introduce a Row_Number function and include that in the where clause, you can effectively join one row to the next row, which would effectively give you a way to accomplish a "has next" functionality.
Related
I'm not clear about below queries and curious to know what is the different between them even though both retrieves same results. (Database used sports2000).
FOR EACH Customer WHERE State = "NH",
FIRST Order OF Customer:
DISPLAY Customer.Cust-Num NAME Order-Num Order-Date.
END.
FOR EACH Customer WHERE State = "NH":
FIND FIRST Order OF Customer NO-ERROR.
IF AVAILABLE Order THEN
DISPLAY Customer.Cust-Num NAME Order-Num Order-Date.
END.
Please explain me
Regards
Suga
As AquaAlex says your first snippet is a join (the "," part of the syntax makes it a join) and has all of the pros and cons he mentions. There is, however, a significant additional "con" -- the join is being made with FIRST and FOR ... FIRST should never be used.
FOR LAST - Query, giving wrong result
It will eventually bite you in the butt.
FIND FIRST is not much better.
The fundamental problem with both statements is that they imply that there is an order which your desired record is the FIRST instance of. But no part of the statement specifies that order. So in the event that there is more than one record that satisfies the query you have no idea which record you will actually get. That might be ok if the only reason that you are doing this is to probe to see if there is one or more records and you have no intention of actually using the record buffer. But if that is the case then CAN-FIND() would be a better statement to be using.
There is a myth that FIND FIRST is supposedly faster. If you believe this, or know someone who does, I urge you to test it. It is not true. It is true that in the case where FIND returns a large set of records adding FIRST is faster -- but that is not apples to apples. That is throwing away the bushel after randomly grabbing an apple. And if you code like that your apple now has magical properties which will lead to impossible to cure bugs.
OF is also problematic. OF implies a WHERE clause based on the compiler guessing that fields with the same name in both tables and which are part of a unique index can be used to join the tables. That may seem reasonable, and perhaps it is, but it obscures the code and makes the maintenance programmer's job much more difficult. It makes a good demo but should never be used in real life.
Your first statement is a join statement, which means less network traffic. And you will only receive records where both the customer and order record exist so do not need to do any further checks. (MORE EFFICIENT)
The second statement will retrieve each customer and then for each customer found it will do a find on order. Because there may not be an order you need to do an additional statement (If Available) as well. This is a less efficient way to retrieve the records and will result in much more unwanted network traffic and more statements being executed.
When I define a CHECK CONSTRAINT on a table, I find the condition clause stored can be different than what I entered.
Example:
Alter table T1 add constraint C1 CHECK (field1 in (1,2,3))
Looking at what is stored:
select cc.Definition from sys.check_constraints cc
inner join sys.objects o on o.object_id = cc.parent_object_id
where cc.type = 'C' and cc.name = 'T1';
I see:
([field1]=(3) OR [field1]=(2) OR [field1]=(1))
Whilst these are equivalent, they are not the same text.
(A similar behaviour occurs when using a BETWEEN clause).
My reason for wishing this did not happen is that I am trying to programatically ensure that all my CHECK constraints are correct by comparing the text I would use to define
the constraint with that stored in sys.check_constraints - and if different then drop and recreate the constraint.
However, in these cases, they are always different and so the program would always think it needs to recreate the constraint.
Question is:
Is there any known reason why SQL Server does this translation? Is it just removing a bit of syntactic sugar and storing the clause in a simpler form?
Is there a way to avoid the behaviour (other than to write my constraint clauses in the long form to match what SQL Server would change it to)?
Is there another way to tell if my check constraint is 'out of date' and needs recreating?
Is there any known reason why SQL Server does this translation? Is it just removing a bit of syntactic sugar and storing the clause in a simpler form?
I'm not aware of any reasons documented in the Books Online, or elsewhere. However, my guess is that it's normalized for some purposes that are internal to SQL Server. It might allow SQL Server to be a bit lenient in defining the expression (such as using Database for a column name), but guaranteeing that the column names are always appropriately escaped for whatever engine needs to parse the expression (ie, [Database]).
Is there a way to avoid the behaviour (other than to write my constraint clauses in the long form to match what SQL Server would change it to)?
Probably not. But if your constraints aren't terribly complicated, is re-writing the constraint clauses in the long form such a bad idea?
Is there another way to tell if my check constraint is 'out of date' and needs recreating?
Before I answer this directly, I'd point out that there's a bit of programming philosophy involved here. The API that SQL Server provides for the text of a CHECK constraint only guarantees that you'll get something equivalent to the original expression. While you could certainly build some fancy methods to try to ensure that you'll always be able to reproduce SQL Server's normalized version of the expression, there's no guarantee that Microsoft won't change its normalization rules in the future. And indeed, there's probably no guarantee that two equivalent expressions will always be normalized identically!
So, I'd first advise you to re-examine your architecture, and see if you can accomplish the same result without having to rely on undocumented API behavior.
Having said that, there are a number of methods outlined in this question (and answer).
Another alternative, which is a bit more brute-force but perhaps acceptable, would be to always assume that the expression is "out of date" and simply drop/re-create the constraint every time you check. Unless you're expecting these constraints to frequently become out-of-date (or the tables are quite large), it seems this would be a decent solution. You could probably even run it in a transaction, so that if the new constraint is already violated, simply roll-back the transaction and report the error.
I’m just starting to convert all of my site’s code into prepared statements for that extra security cushion but I find myself running into the same questions.
After some reading, I’ve decided to use prepared statements on all select queries, however I’m not sure if all of variables in these queries require to be used as “parameters” in the prepared statement.
For example:
Where some_column IS NULL
Where some_column = $_SESSION[‘some-session-var’]
Where some_column IN ($someArray)
Also, is there some way to give each condition a “name” rather than using the question mark? I feel like I’ve seen this before in documentation, but I’ve had no luck finding it since.
For example: Where city_name = :cityName. If so, how would I go about binding the parameters here?
Thanks,
Evan
Yes. All data going to the query should be added via placeholders.
Otherwise there will be no security at all.
Though prepared statements extremely limited and support only scalar values, so, your first and third examples require extra coding (examples can be found in plenty under the tag)
Named placeholders you mentioned belongs to PDO, mysqli don't support them
I am trying to solve a homework problem where I have to return a selected users' grades in
order by course number (not allowed to use built-in sort function). I don't understand the results: the first entry isn't sorted, and some extra students seem to be returned. I don't know why and I spent over three hours trying to solve this one problem. Thanks.
A good start would be to get rid of functions like car, cdr, cadar, ...
Write access functions for the data records. Use first, second and third.
For accessing the list's first element use the function FIRST.
For accessing the rest of the elements use the function REST.
This makes the code easier to read and understand.
Specifically, the concept of set referred to here: http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-16.html#%_sec_2.3.3
I understand how the data structures work and how to traverse through them, but the use of it is tougher to conceptualize.
Would someone mind explaining it in different words, perhaps that might help it click. Thanks so much.
If you have a set (a b c), then trying to insert a into it will result in the same set (a b c). It is just a collection that has the constraint/guarantee that no value will be duplicate.
Example use: You want to find all words used in a text, but their frequencies are irrelevant. If you have a set, then the algorithm is just: go through all words and add each into the set. Since the set automatically throws away all duplicates, it is the correct result when you finish.