Calculate column value based on another column that is calculated - tsql

I need to show the last date enrolled based on value that is derived in the Enrolled column. On this line below WHEN EnrolledDer = 'N' then LAST_DTE_OF_ATTEND. EnrolledDer doesn't exist because it is a derived column. It looks like I have to repeat the case statement to get EnrolledDer for the column to show LAST_DTE_OF_ATTEND for which the alias will be LastDateEnrolledDer. What is the syntax to nest that case statement and is that the best method?
If I try to reference the alias column in the case statement the error is Invalid Column named EnrolledDer'
CASE
WHEN EnrolledDer = 'N' then LAST_DTE_OF_ATTEND --'Invalid Column named EnrolledDer'
Sql Server 2014
SELECT [Student ID],
[Unique Course Identifier],
[Course Title],
Term,
[Section Number],
Days,
[Start Time],
[End Time],
[Start Date],
[End Date],
Enrolled,
--Case, If C then Y, else N
--TRANSACTION_STS Enrolled
--One character code, lookup list value
--C :Current
--D :Dropped
--H :History
--P :Pre-registered
--R :Reserved
--W :Wait listed
CASE
WHEN Enrolled = 'C' THEN 'Y'
ELSE 'N'
END AS "EnrolledDer", --Enrolled Derived Column
--DropFlag,
LAST_DTE_OF_ATTEND LastDateEnrolled, --Populate last date enrolled if enrolled flag above is N
CASE
WHEN EnrolledDer = 'N' then LAST_DTE_OF_ATTEND --'Invalid Column named EnrolledDer'
ELSE NULL
END AS LastDateEnrolledDer, --LastDateEnrolledDer Derived Column
Building,
Room,
ROW_NUMBER() OVER(PARTITION BY [Student ID],
[Unique Course Identifier]
ORDER BY [Start Time]) as rn
FROM cteAccScheduleFull
This related post has test data https://dba.stackexchange.com/questions/308550/convert-7-columns-in-two-rows-to-14-columns-in-one-row/308555#308555
I got this case statement to work with a nested case. I'm not sure what the best way to indent that is. I don't like repeating code. Would another solution be to use a cte or function?
--Populate last date enrolled if enrolled flag above is N
-- CASE
-- WHEN EnrolledDer = 'N' then LAST_DTE_OF_ATTEND
--ELSE NULL
-- END AS LastDateEnrolledDer, --LastDateEnrolledDer Derived Column
CASE
WHEN CASE
WHEN Enrolled = 'C' THEN 'Y'
ELSE 'N'
END
= 'N' then LAST_DTE_OF_ATTEND
ELSE NULL
END AS LastDateEnrolledDer, --LastDateEnrolledDer Derived Column

Aliasing an expression is done through cross apply. Change your FROM to:
FROM
cteAccScheduleFull
cross apply
(select CASE
WHEN Enrolled = 'C' THEN 'Y'
ELSE 'N'
END AS EnrolledDer --Enrolled Derived Column
) as q1
Then you will be able to use q1.EnrolledDer in your select any number of times. You can even chain cross apply blocks if you had more dependent expressions.

Related

Modify values within a column and row (PSQL)

I get the following error for this query: [22P02] ERROR: invalid input syntax for type numeric: "."
select
date,
row_number () over () as RN,
case when (row_number() over ()) ='8' then '.' else (success/trials) end as "After_1M"
from trials
groupy by date;
Is there another way to indicate that a certain value in a ROWxCOLUMN combination should be adjusted?
Well your description certainly leaves a lot to be desired. But your query only needs slight modification to actually run. First off "groupy by date". I will assume it's just a typo. But a group by without an aggregate function generally doesn't do anything - and this is one of those. But I believe your attempting to get a row count by date. If so the you need the partition by and order by clauses in the in the row_number function. The other issue is in the expression. Each entry in the expression must return the same data type but in case it doesn't. The THEN condition returns character (.) while the ELSE returns a numeric (success/trials) which must define 2 numeric columns to be valid. So which needs to change? I will assume the later. Given this we wind up with:
select date
, row_number() over(partition by date order by trl_date) rn
, case when (row_number() over(partition by date order by trl_date)) = 8
then '.'
else (success/trials)::text
end as "After_1M"
from trials;
Note: Date is a very poor date is a very poor column name. It's a reserved word, as well as a data type.

Complex match and Join PostgreSQL

I have the below 3 tables:
Opening transactions, closing transactions and another one with prices (or quotes).
Opening and closing are mirror images of each other. If one is BUY the other is SELL. They are matched by the same txn_id.
INSERT INTO opening_txns (txn_id,txn_timestamp,cust_txn_type,exch_txn_type,currency,amount) VALUES
('0001','2019-01-16 09:00:00.000','SELL','BUY','Euro',1000)
,('0002','2019-01-25 09:00:00.000','BUY','SELL','Euro',1000)
,('0003','2019-01-30 09:00:00.000','BUY','SELL','Euro',1000)
,('0004','2019-02-06 09:00:00.000','SELL','BUY','Euro',1000)
,('0005','2019-02-12 09:00:00.000','SELL','BUY','Euro',1000)
,('0006','2019-02-25 09:00:00.000','BUY','SELL','Euro',1000)
,('0007','2019-03-21 09:00:00.000','BUY','SELL','Euro',1000)
;
INSERT INTO closing_txns (txn_id,txn_timestamp,cust_txn_type,exch_txn_type,currency,amount) VALUES
('0001','2019-03-29 12:00:00.000','BUY','SELL','Euro',1000)
,('0002','2019-03-29 12:00:00.000','SELL','BUY','Euro',1000)
,('0003','2019-03-29 12:00:00.000','SELL','BUY','Euro',1000)
,('0004','2019-03-29 12:00:00.000','BUY','SELL','Euro',1000)
,('0005','2019-03-29 12:00:00.000','BUY','SELL','Euro',1000)
,('0006','2019-03-29 12:00:00.000','SELL','BUY','Euro',1000)
,('0007','2019-03-29 12:00:00.000','SELL','BUY','Euro',1000)
;
INSERT INTO bc_quotes (quote_timestamp,currency,unit,quote_type,"quote") VALUES ('2019-02-25 09:00:00.000','Euro',1,'SELL',1.1375) ,('2019-02-25 09:00:00.000','Euro',1,'BUY',1.1355) ,('2019-03-21 09:00:00.000','Euro',1,'SELL',1.1416) ,('2019-03-21 09:00:00.000','Euro',1,'BUY',1.1392) ,('2019-03-29 12:00:00.000','Euro',1,'BUY',1.1225) ,('2019-03-29 12:00:00.000','Euro',1,'SELL',1.1246) ;
I am looking for the below outcome:
txn_id
amount
sell_price (Find which one of opening or closing txns is a SELL cust_txn. Match the currency, timestamp and exch_txn_type of that transaction with currency, timestamp and quote_type in the bc_quotes table and pick the quote)
buy price (Find which one of opening or closing is a BUY csut_txn. Match the currency, timestamp and exch_txn_type with currency, timestamp and quote_type in the bc_quotes table and pick the quote)
My answer is assuming the columns of opening_txns and closing_txns are of the same type.
Please try the following and tell me if it works for you:
WITH txns AS (
SELECT
txn_id,
amount,
currency,
timestamp,
exch_txn_type
FROM opening_txns
UNION
SELECT
txn_id,
amount,
currency,
timestamp,
exch_txn_type
FROM closing_txns
)
SELECT
txn_id,
amount,
CASE WHEN cust_txn_type = 'SELL' THEN quote ELSE NULL END AS sell_price,
CASE WHEN cust_txn_type = 'BUY' THEN quote ELSE NULL END AS buy_price
FROM txns T
LEFT JOIN bc_quotes Q
ON (T.currency = Q.currency AND T.timestamp = Q.timestamp AND T.exch_txn_type = Q.quote_type);
Explanations:
txns is a common table expression to help clarify the query.
Since both opening_txns and closing_txns share the same columns,
you can use UNION to effectively merge two results sets into one
txns result set.
Then you can use LEFT JOIN to match the rows of
txns to their respective quotes using the conditions provided in
the ON clause.
Lastly, you can use the conditional CASE statement
in the SELECT to distinguish between 'SELL' and 'BUY
transactions; if the transaction is a 'BUY' (resp. 'SELL'), then
the buy_price column will be quote and sell_price will be
NULL.
The final result set has the following columns: txn_id, amount and sell_price, buy_price.
I hope this helps.

how to put nested case-when condition in postgresql query

i want to write nested case when condition in query to store the value that will come from one case when condition and another case when condition into same new column.to get this kind of result i am writing the query as:
(case when sq_name_new1 like format('%%%s%%',demo.name) THEN count(sq_name_new1) else (when demo.empcode is not null then count(demo.id) End) END) AS indivisual from res_scheduledjobs
in the above query demo.name column comes from CTE.so my whole query look like:
with demo(empcode,id,name) as
(select hr_employee.emp_code,hr_employee.id,concat(resource_resource.name,' ',hr_employee.middle_name,' ',hr_employee.last_name) as name from hr_employee inner join resource_resource on resource_resource.id=hr_employee.resource_id)
select demo.empcode,demo.name,sq_name_new1,(case when sq_name_new1 like format('%%%s%%',demo.name) THEN count(sq_name_new1) else (when demo.empcode is not null then count(demo.id) End) END) AS indivisual from res_scheduledjobs LEFT JOIN demo on demo.id=res_scheduledjobs.assigned_technician group by res_scheduledjobs.assigned_technician,sq_name_new1,demo.empcode,demo.name ;
i just want to store the count of (sq_name_new1) column into INDIVISUAL Column and the count of (demo.id) column into same column,that is in INDIVISUAL,if the first case condition does not match.
but when i am executing my query it throw an error.that is,something is wrong in the syntax of case when condition.
please help me yo write the correct nested case-when condition.
CASE ... WHEN ... END is an expression. It can be nested like any other expression.
CASE
WHEN condition THEN
CASE
WHEN othercondition THEN
....
END
END
The first semicolon ; should be removed as in #Craig Ringer's answer.
SELECT
CASE WHEN condition1 THEN
CASE
WHEN condition1.1 THEN
...
END
END AS column_name
FROM table_name;

Filtering stored procedure records by nested select case statement

I need to further refine my stored proc resultset from this post, I need to filter my resultset to display only records where emailaddr is NULL (meaning display only records that have Invoice_DeliveryType value of 'N' ).
Among numerous queries, I have tried:
select
Invoice_ID, 'Unknown' as Invoice_Status,
case when Invoice_Printed is null then '' else 'Y' end as Invoice_Printed,
case when Invoice_DeliveryDate is null then '' else 'Y' end as Invoice_Delivered,
(case when Invoice_DeliveryType <> 'USPS' then ''
when exists (Select 1
from dbo.Client c
Where c.Client_ID = SUBSTRING(i.Invoice_ID, 1, 6) and
c.emailaddr is not null
)
then 'Y'
else 'N'
end)
Invoice_ContactLName + ', ' + Invoice_ContactFName as ContactName,
from
dbo.Invoice
left outer join
dbo.fnInvoiceCurrentStatus() on Invoice_ID = CUST_InvoiceID
where
CUST_StatusID = 7
AND Invoice_ID = dbo.Client.Client_ID
AND dbo.client.emailaddr is NULL
order by
Inv_Created
but I get an error
The conversion of the nvarchar value '20111028995999' overflowed an int column
How can I get the stored procedure to only return records with DeliveryType = 'N' ?
Trying selecting the stored proc results into a temp table, then select
* from #TempTable
We could really do with a schema definition to get this problem resolved.
It appears that there is an implicit conversion occurring within one of your case statements, but without the schema def's it's difficult to track down which one.
You can't safely mix datatypes in CASE expressions, unless you are absolutely sure that any implicit conversions will work out OK you should make the conversions explicit.
Judging by the error message seeming to include something that could be a date represented as a string(20111028) plus some kind of other data ?time?(995999) it may be something to do with Invoice_DeliveryDate, but this is a shot in the dark without more details.

Unexpected SQL results: string vs. direct SQL

Working SQL
The following code works as expected, returning two columns of data (a row number and a valid value):
sql_amounts := '
SELECT
row_number() OVER (ORDER BY taken)::integer,
avg( amount )::double precision
FROM
x_function( '|| id || ', 25 ) ca,
x_table m
WHERE
m.category_id = 1 AND
m.location_id = ca.id AND
extract( month from m.taken ) = 1 AND
extract( day from m.taken ) = 1
GROUP BY
m.taken
ORDER BY
m.taken';
FOR r, amount IN EXECUTE sql_amounts LOOP
SELECT array_append( v_row, r::integer ) INTO v_row;
SELECT array_append( v_amount, amount::double precision ) INTO v_amount;
END LOOP;
Non-Working SQL
The following code does not work as expected; the first column is a row number, the second column is NULL.
FOR r, amount IN
SELECT
row_number() OVER (ORDER BY taken)::integer,
avg( amount )::double precision
FROM
x_function( id, 25 ) ca,
x_table m
WHERE
m.category_id = 1 AND
m.location_id = ca.id AND
extract( month from m.taken ) = 1 AND
extract( day from m.taken ) = 1
GROUP BY
m.taken
ORDER BY
m.taken
LOOP
SELECT array_append( v_row, r::integer ) INTO v_row;
SELECT array_append( v_amount, amount::double precision ) INTO v_amount;
END LOOP;
Question
Why does the non-working code return a NULL value for the second column when the query itself returns two valid columns? (This question is mostly academic; if there is a way to express the query without resorting to wrapping it in a text string, that would be great to know.)
Full Code
http://pastebin.com/hgV8f8gL
Software
PostgreSQL 8.4
Thank you.
The two statements aren't strictly equivalent.
Assuming id = 4, the first one gets planned/prepared on each pass, and behaves like:
prepare dyn_stmt as '... x_function( 4, 25 ) ...'; execute dyn_stmt;
The other gets planned/prepared on the first pass only, and behaves more like:
prepare stc_stmt as '... x_function( $1, 25 ) ...'; execute stc_stmt(4);
(The loop will actually make it prepare a cursor for the above, but that's besides the point for our sake.)
A number of factors can make the two yield different results.
Search path changes before calling the procedure will be ignored by the second call. In particular if this makes x_table point to something different.
Constants of all kinds and calls to immutable functions are "hard-wired" in the second call's plan.
Consider this as an illustration of these side-effects:
deallocate all;
begin;
prepare good as select now();
prepare bad as select current_timestamp;
execute good; -- yields the current timestamp
execute bad; -- yields the current timestamp
commit;
execute good; -- yields the current timestamp
execute bad; -- yields the timestamp at which it was prepared
Why the two aren't returning the same results in your case would depend on the context (you only posted part of your pl/pgsql function, so it's hard to tell), but my guess is you're running into a variation of the above kind of problem.
From Tom Lane:
I think the problem is that you're assuming "amount" will refer to a table column of the query, when actually it's a local variable of the plpgsql function. The second interpretation will take precedence unless you qualify the column reference with the table's name/alias.
Note: PG 9.0 will throw an error by default when there is an ambiguity of this type.