MS SQL Server: Operate current select values in other selected columns - sql

I want to take a value from a selected column to operate the next column. For example:
SELECT CASE
WHEN ID < 4 THEN ID
ELSE 10
END
AS MY_ID,
MY_ID + 5 AS EXTRA_ID
FROM FOO
That would output for IDs 1,2,3,4,5:
MY_ID EXTRA_ID
1 6
2 7
3 8
10 15
10 15
If I do MY_ID + 5 it will complain about MY_ID not existing (it's an alias, so it makes sense) and ID + 5 will read 1+5, 2+5, 3+5, 4+5, 5+5 instead of 1+5, 2+5, 3+5, 4+10, 5+10 when it goes through the ELSE. Is it even possible to do this? I'm doing it in SSRS - Report builder, and need to operate a result that might be set to a defualt value depending on the CASE clause.

You can repeat the same CASE expression with +5 in the end for the extra_id column
SELECT CASE
WHEN ID < 4 THEN ID
ELSE 10
END
AS MY_ID,
CASE
WHEN ID < 4 THEN ID
ELSE 10
END + 5 AS EXTRA_ID
FROM FOO
An alternative is to create the extra_id column value inside SSRS using an expression
= Fields!my_id.value + 5

you cannot reuse the calculation in the same level. Using my_id in the where clause will fail as well. Either you have to calucate it multiple times, place another select around your statement or use a with statement (CTE).

Simply wrap it with another select:
SELECT t.*,
t.my_id + 5 as extra_id
FROM(Your Query) t
Derived columns are not available in the same layer they're being created. By wrapping them with another select, you make them available (that because the inner query is being processed before the outer) .

You just need a subquery to create MY_ID before doing anything with it. By creating MY_ID in the inner query the outer query can use to define new fields.
SELECT
a.MY_ID,
a.MY_ID + 5 AS EXTRA_ID
from
(SELECT
CASE
WHEN ID < 4 THEN ID
ELSE 10
END
AS MY_ID
FROM FOO) as a

Related

How to set flag based on values in previous columns in same table ? (Oracle)

I'm creating a new table and carrying over several columns from a previous table. One of the new fields that I need to create is a flag that will have values 0 or 1 and value needs to be determined based on 6 previous fields in the table.
The 6 previous columns have preexisting values of 0 or 1 stored for each one. This new field needs to check whether any of the 6 columns have 1 and if so set the flag to 0. If there is 0 in all 6 fields then set itself to 1.
Hopefully this makes sense. How can I get this done in oracle? I assume a case statement and some sort of forloop?
You can use greatest() function: GREATEST
create table t_new
as
select
case when greatest(c1,c2,c3,c4,c5,c6)=1 -- at least one of them contains 1
then 0
else 1
end c_new
from t_old;
Or even shorter:
create table t_new
as
select
1-greatest(c1,c2,c3,c4,c5,c6) as c_new
from t_old;
In case of greatest = 1, (1-1)=0, otherwise (1-0)=1
You can use a virtual column with a case expression; something like:
flag number generated always as (
case when val_1 + val_2 + val_3 + val_4 + val_5 + val_6 = 0 then 1 else 0 end
) virtual
db<>fiddle
or the same thing with greatest() as #Sayan suggested.
Using a virtual column means the flag will be right for newly-inserted rows, and if any of the other values are updated; you won't have to recalculate or update the flag column manually.
I've assumed the other six columns can't be null and are constrained to only be 0 or 1, as the question suggests. If they can be null you can add nvl() or coalesce() to each term in the calculation.

How to return NULL records on a query with a where clause?

I'm using SQL Server 2016 and I have a view setup for novice end users.
To start, let's say there is a table like the following:
id number
=========
1 2
2 4
3 6
4 NULL
5 12
If a user makes a query on the view such as, select * from view1 where number <> 12, the view is setup to return NULL values as -99 using coalesce(number,-99):
Result of 'select * from view1 where number <> 12':
id number
=========
1 2
2 4
3 6
4 -99
Is there anyway to have the view return NULL instead of -99 (or whatever value), without the end user having to include ... or where is null in their query?
I understand NULLs and why it behaves like this, but for convenience I'd rather these end users not have to do this.
No.
The best you can do is fix the result so it decodes -99 as NULL:
SELECT id, CASE WHEN number = -99 THEN NULL ELSE number END AS number
FROM view1
WHERE number != 12
which I believe defeats the purpose of not exposing NULL values to the end user, or approach the data by accounting NULL as a valid data, using OR number IS NULL in that matter.
Try this:
select * from view1 where number <> 12 or number is null

MonetDB: Enumerate groups of rows based on a given "boundary" condition

Consider the following table:
id gap groupID
0 0 1
2 3 1
3 7 2
4 1 2
5 5 2
6 7 3
7 3 3
8 8 4
9 2 4
Where groupID is the desired, computed column, such as its value is incremented whenever the gap column is greater than a threshold (in this case 6). The id column defines the sequential order of appearance of the rows (and it's already given).
Can you please help me figure out how to dynamically fill out the appropriate values for groupID?
I have looked in several other entries here in StackOverflow, and I've seen the usage of sum as an aggregate for a window function. I can't use sum because it's not supported in MonetDB window functions (only rank, dense_rank, and row_num). I can't use triggers (to modify the record insertion before it takes place) either because I need to keep the data mentioned above within a stored function in a local temporary table -- and trigger declarations are not supported in MonetDB function definitions.
I have also tried filling out the groupID column value by reading the previous table (id and gap) into another temporary table (id, gap, groupID), with the hope that this would force a row-by-row operation. But this has failed as well because it gives the groupID 0 to all records:
declare threshold int;
set threshold = 6;
insert into newTable( id, gap, groupID )
select A.id, A.gap,
case when A.gap > threshold then
(select case when max(groupID) is null then 0 else max(groupID)+1 end from newTable)
else
(select case when max(groupID) is null then 0 else max(groupID) end from newTable)
end
from A
order by A.id asc;
Any help, tip, or reference is greatly appreciated. It's been a long time already trying to figure this out.
BTW: Cursors are not supported in MonetDB either --
You can assign the group using a correlated subquery. Simply count the number of previous values that exceed 6:
select id, gap,
(select 1 + count(*)
from t as t2
where t2.id <= t.id and t2.gap > 6
) as Groupid
from t;

Calculating a field from SQL Query Selecting from multiple tables with Union

I have the following query, which works great. The problem I have is that in both tables (and the aggregate unioned table), there is a field called MTGUID. I need to multiply MTGUID by a number (let's say 1.35, for ease of use) and have it return that number in the MTGUID field. I have tried a dozen ways to do this and can't get anything to play ball. I can create a new column for each calculated price, like (BKRETAIL.MTGUID * 1.35) AS MTG1, but we've got tens of thousands of lines of code that specifically use MTGUID. Any ideas?
I'm using Firebird SQL.
SELECT * FROM (
SELECT BKRETAIL.* FROM BKRETAIL WHERE BKRETAIL.MKEY='SOMEKEY'
UNION SELECT BKWHOLESALE.* FROM BKWHOLESALE WHERE MKEY='SOMEKEY')
ORDER BY
case STATUS
WHEN 'RT' then 1
WHEN 'WH' then 2
WHEN 'OL' then 3
WHEN 'OD' then 4
WHEN NULL then 5
else 6
end;
How about this:
SELECT MTGUID * 1.35 as calculatedMTGUID, SUBSEL.* FROM (
SELECT BKRETAIL.* FROM BKRETAIL WHERE BKRETAIL.MKEY='SOMEKEY'
UNION SELECT BKWHOLESALE.* FROM BKWHOLESALE WHERE MKEY='SOMEKEY') SUBSEL
ORDER BY
case STATUS
WHEN 'RT' then 1
WHEN 'WH' then 2
WHEN 'OL' then 3
WHEN 'OD' then 4
WHEN NULL then 5
else 6
end;
try this
SELECT MTGUID * 1.35 AS MTGUID,<list rest OF COLUMNS here>
FROM (
SELECT BKRETAIL.* FROM BKRETAIL WHERE BKRETAIL.MKEY='SOMEKEY'
UNION SELECT BKWHOLESALE.* FROM BKWHOLESALE WHERE MKEY='SOMEKEY')
ORDER BY
case STATUS
WHEN 'RT' then 1
WHEN 'WH' then 2
WHEN 'OL' then 3
WHEN 'OD' then 4
WHEN NULL then 5
else 6
end;
One option would be to replace the original MTGUID column with computed one, ie
rename the original MTGUID column in table(s);
add new MTGUID column with desired expression using COMPUTED BY (expr);
Advantage of this is that you don't have to alter your SQL statements, disadvantage is that you have to maintain the expression in many places (all the tables which have the column). Of course, the queries which need the original MTGUID value must be updated to use the renamed column, but if the number of such statements is significantly lower it could be worth the trouble.
I think a better solution would be to "hide" all this stuff behind a view but this requires alerting your SQL queries...

SQL Access db - select every third row from database

How can I select every thrid row from the table?
if a table has
1
2
3
4
5
6
7
8
9
records
it should pick up 3, 6,9 record. regards less what their data is.
Modulo is what you want...
Assuming contiguous values:
SELECT *
FROM Mytable
WHERE [TheColumn] Mod 3 = 0
And with gaps
SELECT *
FROM Mytable
WHERE DCount("TheColumn", "table", "TheColumn <= " & [TheColumn]) Mod 3 = 0
Edit: To exclude every 3rd record, ...Mod 3 <> 0
If its SQL you could use the row_number and over commands. see this, then where rownumvar % 3 =0 but not sure if that works in access.
Or you could put the table into a recordset and iterate through checking the index for % 3=0 if your using any kind of code.
How about a Count() on a field that has unique members. (id?) then % 3 on that.