I have two tables like below:
How can I calculate ID PAY2 formula value of empid E001. Calculate like: parameter1 = basic and basic of E001 = 1000.
So as per formula if PAY1>4000 then PAY5 (may be value is 200 of parameter5)
So for E001 basic is 1000 and it is false against if condition and value should be {PAY1}/100 like 1000/100=10.
Is it possible to execute if and else condition in a column and calculate its value?
If I interpret your question correctly, you want to be able to embed formulae within your database, and execute those formulae to calculate pay.
This is a hard problem to solve - you're basically trying to implement a min programming language in SQL.
I assume you want this feature because the business rules may change (or at least the parameters) and you don't want to have to spend developer time when that happens.
If you can express the formulae as SQL, you can use dynamic SQL (the exec feature), but this may be error prone, and subject to abuse - if you allow people to store executable SQL code as data, a small bug in that code could wipe out all your data. It's also hard to test.
It's very likely that developers would have to write the dynamic SQL statements anyway, so you're unlikely to achieve your goal.
If you can distinguish between "algorithm" and "parameters", you could make those parameters editable by non-technical users, and only need to involve developers when the algorithm changes. You could store the parameters in a database table (and give them better names than "parameter_n"). This is one of the few occasions when an entity/attribute/value store makes sense, though it would be better to encode this as XML or JSON in the database, as that would allow you to declare a schema (and test against it!).
Your example might become:
select #allowance = (
select value
from parameters
where key = 'default_allowance')
where pay > (
select value
from parameters
where key = 'min_pay_for_allowance');
select #allowance = pay / (
select value
from parameters
where key = 'pay_divisor_for_allowance)
where pay <= (
select value
from parameters
where key = 'min_pay_for_allowance');
Related
Thank you for checking my question out!
I'm trying to write a query for a very specific problem we're having at my workplace and I can't seem to get my head around it.
Short version: I need to be able to target columns by their name, and more specifically by a part of their name that will be consistent throughout all the columns I need to combine or compare.
More details:
We have (for example), 5 different surveys. They have many questions each, but SOME of the questions are part of the same metric, and we need to create a generic field that keeps it. There's more background to the "why" of that, but it's pretty important for us at this point.
We were able to kind of solve this with either COALESCE() or CASE statements but the challenge is that, as more surveys/survey versions continue to grow, our vendor inevitably generates new columns for each survey and its questions.
Take this example, which is what we do currently and works well enough:
CASE
WHEN SURVEY_NAME = 'Service1' THEN SERV1_REC
WHEN SURVEY_NAME = 'Notice1' THEN FNOL1_REC
WHEN SURVEY_NAME = 'Status1' THEN STAT1_REC
WHEN SURVEY_NAME = 'Sales1' THEN SALE1_REC
WHEN SURVEY_NAME = 'Transfer1' THEN Null
ELSE Null
END REC
And also this alternative which works well:
COALESCE(SERV1_REC, FNOL1_REC, STAT1_REC, SALE1_REC) as REC
But as I mentioned, eventually we will have a "SALE2_REC" for example, and we'll need them BOTH on this same statement. I want to create something where having to come into the SQL and make changes isn't needed. Given that the columns will ALWAYS be named "something#_REC" for this specific metric, is there any way to achieve something like:
COALESCE(all columns named LIKE '%_REC') as REC
Bonus! Related, might be another way around this same problem:
Would there also be a way to achieve this?
SELECT (columns named LIKE '%_REC') FROM ...
Thank you very much in advance for all your time and attention.
-Kendall
Table and column information in Db2 are managed in the system catalog. The relevant views are SYSCAT.TABLES and SYSCAT.COLUMNS. You could write:
select colname, tabname from syscat.tables
where colname like some_expression
and syscat.tabname='MYTABLE
Note that the LIKE predicate supports expressions based on a variable or the result of a scalar function. So you could match it against some dynamic input.
Have you considered storing the more complicated properties in JSON or XML values? Db2 supports both and you can query those values with regular SQL statements.
For a stock market app I've coded a stored procedure with
SELECT [Stockname, Price]
FROM [StocksTable]
WHERE Currency IN [UserDefinedTableOfCurrencyCodes]
However, when the user wants to see all prices regardless of Currency it is obviously inefficient to include a WHERE clause at all -- but the only/best way to accomplish this that I can see is to have an IF clause in the stored procedure.
Am I so noob as to be missing a better solution? (note the real app has four different possible WHERE criteria rather than just Currencies so the IF logic might get complicated. P.S> I realize the IF statement could be webserver or even front side and point to different stored procedures but at this development stage at least prefer to keep control/design in my db).
EDIT/UPDATE: FYI Apparently SQL Server turns an IN clause into a series of OR clauses.
If you have any parameter for user wants to see all currency, for example, like #ShowAllCurrency, you can change query like this.
WHERE (#ShowAllCurrency = 1
OR Currency IN [UserDefinedTableOfCurrencyCodes] )
If #ShowAllCurrency == 1 equal true, sql not look for IN part.
If there is a need to show all records regardless of currency, then yes, you won't need a WHERE clause for that.
If you write a clause that says WHERE Currency IN ([every currency you have]) then the database may just process that in the same way as not having a where clause (from what I understand, but I may be wrong).
I've been trawling around in the internet for a demo on second order SQLi but I still haven't found one yet. Many sites don't really give a thorough explanation on how it works.
I need to present a short demonstration and I've been practicing using Mutillidae. Can anybody lead me in the right direction?
A Google search for 'second order sql injection' comes up with a number of more or less relevant explanations of what Second Order SQL Injection is, with differing degrees of detail (as you say).
The basic idea is that the database stores some text from the user that is later incorporated into an SQL statement — but the text is insufficiently sanitized before reuse.
Think of an application which allows a user to create user-defined queries against a database. A simple example might be a bug tracking system. Some of the user-defined query attributes might be simple conditions such as 'bug status is "closed"'. This might be coded by looking at the stored query definition:
CREATE TABLE UserDefinedQuery
(
...user info...,
bug_status VARCHAR(20),
...other info...
);
SELECT ..., bug_status, ...
INTO ..., hv_bug_status, ...
FROM UserDefinedQuery
WHERE bug_status IS NOT NULL
AND ...other criteria...
where hv_bug_status is a host variable (PHP, C, whatever language you're using) holding the bug status criterion.
If this value is = 'closed', then the resulting SQL might contain:
SELECT *
FROM Bugs
WHERE status = 'closed'
AND ...other criteria...
Now suppose that when the user defined their query, they wrote instead:
= 'open' or 1=1
This means that the generated query now looks like:
SELECT *
FROM Bugs
WHERE status = 'open' or 1=1
AND ...other criteria...
The presence of the OR changes the meaning of the query dramatically and will show all sorts of other records that were not the ones that the user was intended to see. This is a bug in the bug querying application. If this modification means that CustomerX can see bugs reported by other customers CustomerY and CustomerZ that they are not supposed to see, then CustomerX has managed to create a second order SQL injection attack. (If the injection simply means that they get to see more records than they should, including ones that aren't relevant to them, then they've simply created a buggy query.)
Clearly, in a VARCHAR(20) field, your options for injecting lethal SQL are limited simply because SQL is a verbose language. But 'little Bobby Tables' could strike if the criteria are stored in a longer field.
='';DELETE Bugs;--
(Using a non-standard contraction for the DELETE statement; that squeaks in at 18 characters.)
How can you avoid this? Don't allow the user to write raw SQL fragments that you include in the generated SQL. Treat the value in UserDefinedQuery.Bug_Status as a space/comma separated list of string values, and build the query accordingly:
SELECT *
FROM Bugs
WHERE status IN ('=', '''open''', 'or', '1=1')
AND ...other criteria...
The query may not be useful, but it doesn't get its structure altered by the data in the UserDefinedQuery table.
Browsing through the more dubious parts of the web, I happened to come across this particular SQL injection:
http://server/path/page.php?id=1+union+select+0,1,concat_ws(user(),0x3a,database(),0x3a,version()),3,4,5,6--
My knowledge of SQL - which I thought was half decent - seems very limiting as I read this.
Since I develop extensively for the web, I was curious to see what this code actually does and more importantly how it works.
It replaces an improperly written parametrized query like this:
$sql = '
SELECT *
FROM products
WHERE id = ' . $_GET['id'];
with this query:
SELECT *
FROM products
WHERE id = 1
UNION ALL
select 0,1,concat_ws(user(),0x3A,database(),0x3A,version()),3,4,5,6
, which gives you information about the database name, version and username connected.
The injection result relies on some assumptions about the underlying query syntax.
What is being assumed here is that there is a query somewhere in the code which will take the "id" parameter and substitute it directly into the query, without bothering to sanitize it.
It's assuming a naive query syntax of something like:
select * from records where id = {id param}
What this does is result in a substituted query (in your above example) of:
select * from records where id = 1 union select 0, 1 , concat_ws(user(),0x3a,database(),0x3a,version()), 3, 4, 5, 6 --
Now, what this does that is useful is that it manages to grab not only the record that the program was interested in, but also it UNIONs it with a bogus dataset that tells the attacker (these values appear separated by colons in the third column):
the username with which we are
connected to the database
the name of the database
the version of the db software
You could get the same information by simply running:
select concat_ws(user(),0x3a,database(),0x3a,version())
Directly at a sql prompt, and you'll get something like:
joe:production_db:mysql v. whatever
Additionally, since UNION does an implicit sort, and the first column in the bogus data set starts with a 0, chances are pretty good that your bogus result will be at the top of the list. This is important because the program is probably only using the first result, or there is an additional little bit of SQL in the basic expression I gave you above that limits the result set to one record.
The reason that there is the above noise (e.g. the select 0,1,...etc) is that in order for this to work, the statement you are calling the UNION with must have the same number of columns as the first result set. As a consequence, the above injection attack only works if the corresponding record table has 7 columns. Otherwise you'll get a syntax error and this attack won't really give you what you want. The double dashes (--) are just to make sure anything that might happen afterwords in the substitution is ignored, and I get the results I want. The 0x3a garbage is just saying "separate my values by colons".
Now, what makes this query useful as an attack vector is that it is easily re-written by hand if the table has more or less than 7 columns.
For example if the above query didn't work, and the table in question has 5 columns, after some experimentation I would hit upon the following query url to use as an injection vector:
http://server/path/page.php?id=1+union+select+0,1,concat_ws(user(),0x3a,database(),0x3a,version()),3,4--
The number of columns the attacker is guessing is probably based on an educated look at the page. For example if you're looking at a page listing all the Doodads in a store, and it looks like:
Name | Type | Manufacturer
Doodad Foo Shiny Shiny Co.
Doodad Bar Flat Simple Doodads, Inc.
It's a pretty good guess that the table you're looking at has 4 columns (remember there's most likely a primary key hiding somewhere if we're searching by an 'id' parameter).
Sorry for the wall of text, but hopefully that answers your question.
this code adds an additional union query to the select statement that is being executed on page.php. The injector has determined that the original query has 6 fields, thus the selection of the numeric values (column counts must match with a union). the concat_ws just makes one field with the values for the database user , the database, and the version, separated by colons.
It seems to retrieve the user used to connect to the database, the database adress and port, the version of it. And it will be put by the error message.
I have a data driven site with many stored procedures. What I want to eventually be able to do is to say something like:
For Each #variable in sproc inputs
UPDATE #TableName SET #variable.toString = #variable
Next
I would like it to be able to accept any number of arguments.
It will basically loop through all of the inputs and update the column with the name of the variable with the value of the variable - for example column "Name" would be updated with the value of #Name. I would like to basically have one stored procedure for updating and one for creating. However to do this I will need to be able to convert the actual name of a variable, not the value, to a string.
Question 1: Is it possible to do this in T-SQL, and if so how?
Question 2: Are there any major drawbacks to using something like this (like performance or CPU usage)?
I know if a value is not valid then it will only prevent the update involving that variable and any subsequent ones, but all the data is validated in the vb.net code anyway so will always be valid on submitting to the database, and I will ensure that only variables where the column exists are able to be submitted.
Many thanks in advance,
Regards,
Richard Clarke
Edit:
I know about using SQL strings and the risk of SQL injection attacks - I studied this a bit in my dissertation a few weeks ago.
Basically the website uses an object oriented architecture. There are many classes - for example Product - which have many "Attributes" (I created my own class called Attribute, which has properties such as DataField, Name and Value where DataField is used to get or update data, Name is displayed on the administration frontend when creating or updating a Product and the Value, which may be displayed on the customer frontend, is set by the administrator. DataField is the field I will be using in the "UPDATE Blah SET #Field = #Value".
I know this is probably confusing but its really complicated to explain - I have a really good understanding of the entire system in my head but I cant put it into words easily.
Basically the structure is set up such that no user will be able to change the value of DataField or Name, but they can change Value. I think if I were to use dynamic parameterised SQL strings there will therefore be no risk of SQL injection attacks.
I mean basically loop through all the attributes so that it ends up like:
UPDATE Products SET [Name] = '#Name', Description = '#Description', Display = #Display
Then loop through all the attributes again and add the parameter values - this will have the same effect as using stored procedures, right??
I dont mind adding to the page load time since this is mainly going to affect the administration frontend, and will marginly affect the customer frontend.
Question 1: you must use dynamic SQL - construct your update statement as a string, and run it with the EXEC command.
Question 2: yes there are - SQL injection attacks, risk of mal-formed queries, added overhead of having to compile a separate SQL statement.
Your example is very inefficient, so if I pass in 10 columns you will update the same table 10 times?
The better way is to do one update by using sp_executesql and build this dynamically, take a look at The Curse and Blessings of Dynamic SQL to see how you have to do it
Is this a new system where you have the freedom to design as necessary, or are you stuck with an existing DB design?
You might consider representing the attributes not as columns, but as rows in a child table.
In the parent MyObject you'd just have header-level data, things that are common to all objects in the system (maybe just an identifier). In the child table MyObjectAttribute you'd have a primary key of with another column attrValue. This way you can do an UPDATE like so:
UPDATE MyObjectAttribute
SET attrValue = #myValue
WHERE objectID = #myID
AND attrName = #myAttrName