Assign a case value to a column rather than an alias - sql

This should be a simple one, but I have not found any solution:
The normal way is using an alias like this:
CASE WHEN ac_code='T' THEN 'time' ELSE 'purchase' END as alias
When using alias in conjunction with UNION ALL this causes problem because the alias is not treated the same way as the other columns.
Using an alias to assign the value is not working. It is still treated as alias, though it has the column name.
CASE WHEN ac_code='T' THEN 'time' ELSE 'purchase' END as ac_subject
I want to assign a value to a column based on a condition.
CASE WHEN ac_code='T' THEN ac_subject ='time' ELSE ac_subject='purchase' END
Now I get the error message
UNION types character varying and boolean cannot be matched
How can I assign a value to a column in a case statement without using an alias in the column (shared by other columns in UNION)?
Here is the whole (simplified) query:
SELECT hr_id,
CASE WHEN hr_subject='' THEN code_name ELSE hr_subject END
FROM hr
LEFT JOIN code ON code_id=hr_code
WHERE hr_job='123'
UNION ALL
SELECT po_id,
CASE WHEN po_subject='' THEN code_name ELSE po_subject END
FROM po
LEFT JOIN code ON code_id=po_code
WHERE po_job='123'
UNION ALL
SELECT ac_id,
CASE WHEN ac_code='T' THEN ac_subject='time' ELSE ac_subject='purchase' END
FROM ac
WHERE ac_job='123'

There is no alias in your presented query. You are confusing terms. This would be a column alias:
CASE WHEN hr_subject='' THEN code_name ELSE hr_subject END AS ac_subject
In a UNION query, the number of columns, column names and data types in the returned set are determined by the first row. All appended rows have to match the row type. Column names in appended rows (including aliases) are just noise and ignored. Maybe useful for documentation, nothing else.
The = operator does not assign anything in a SELECT query. It's the equality operator that returns a boolean value. TRUE if both operands are equal, etc. This returns a boolean value: ac_subject='time' Hence your error message:
UNION types character varying and boolean cannot be matched
The only way to "assign" a value to a particular output column in this query is to include it at the right position in the SELECT list.
The information in the question is incomplete, but I suspect you are also confusing the empty string ('') with the NULL value. A distinction that you need to understand before doing anything else with relational databases. Maybe start here. In this case you would rather use COALESCE to provide a default for NULL values:
SELECT hr_id, COALESCE(hr_subject, code_name) AS ac_subject
FROM hr
LEFT JOIN code ON code_id=hr_code
WHERE hr_job = '123'
UNION ALL
SELECT po_id, COALESCE(po_subject, code_name)
FROM po
LEFT JOIN code ON code_id=po_code
WHERE po_job = '123'
UNION ALL
SELECT ac_id, CASE WHEN ac_code = 'T' THEN 'time'::varchar ELSE 'purchase' END
FROM ac
WHERE ac_job = '123'
Just an educated guess, assuming type varchar. You should have added table qualification to column names to clarify their origin. Or table definitions to clarify everything.

The CASE expression is supposed to return a value, e.g. 'time'.
Your value is another expression subject ='time' which is a boolean (true or false).
Is this on purpose? Does the other query you glue with UNION have a boolean in that place, too? Probably not, and this is what the DBMS complains about.

I found the problem.
CASE WHEN hr_subject=’’ THEN code_name ELSE hr_subject END
The columns code_name and hr_subject was different length. This caused the unpredictable result. I think that aliases can work now.
Thank you for your support.

Related

REPLACE not doing what I need in SQL

I've got a query pulling data from a table. In one particular field, there are several cases where it is a zero, but I need the four digit location number. Here is where I'm running into a problem. I've got
SELECT REPLACE(locationNbr, '0', '1035') AS LOCATION...
Two issues -
Whoever put the table together made all fields VARCHAR, hence the single quotes.
In the cases where there already is the number 1035, I get 1103535 as the location number because it's replacing the zero in the middle of 1035.
How do I select the locationNbr field and leave it alone if it's anything other than zero (as a VARCHAR), but if it is zero, change it to 1035? Is there a way to somehow use TO_NUMBER within the REPLACE?
SELECT CASE WHEN locationNbr='0' THEN '1035' ELSE locationNbr END AS LOCATION...
REPLACE( string, string_to_replace , replacement_string )
REPLACE looks for a string_to_replace inside a string and replaces it with a replacent_string. That is why you get the undesired behaviour - you are using the wrong function.
CASE WHEN condition THEN result1 ELSE result2 END
CASE checks a condition and if it is true it returns result1 and if it is not it will return result2. This is a simple example, you can write a case statement with more than one condition check.
Don't use replace(). Use case:
(case when locationNbr = '0' then '1035' else locationNbr end)
You can make use of length in Oracle:
select case when length(loacation) = 1 then REPLACE(loacation, '0', '1035') else loacation end as location
from location_test;

SQL - if something then do this if nothing do nothing

I have a column with many nulls in table 1, but now and then there is a value. If there is a value, I want to go to table 2 and take the the corresponding value from there. This should create an extra column called user_original:
CASE
WHEN table1.user_changed IS NOT NULL
THEN table2.user_original
ELSE -- do nothing
END as user_original
I basically want to replace
is nothing
Is this correct ? How can this be done? Is there a better way?
do you mean you need below
CASE
WHEN table1.user_changed IS NOT NULL
THEN table2.user_original
END as user_original
Do you want a correlated subquery?
(CASE WHEN table1.user_changed IS NOT NULL
THEN (SELECT table2.user_original FROM table2 WHERE table2.? = table1.?)
END) as user_original
The ? is for the columns that identifying "corresponding" values.
If this is the case, you can probably simplify this to:
(SELECT table2.user_original FROM table2 WHERE table2.? = table1.?) as user_original
My guess is there will be no matching value if the original value is NULL.

Force result for field as 'NULL' when document was posted after a certain date

I have a query that I am pulling in a department field, however, after a certain date I want this field to be populated as null.
For example, here is the code
Select T6.Segment2 as 'Old Department Code'
I do want this field to pull in the appropriate values, however after a certain date ( 04/01/2019 ) I want this field to show a NULL value.
Is this possible?
Not sure which DBMS you are using but it is basically the same for all of them when it comes to this... You want to use a CASE statement.
What this essentially does is it acts as an IF ELSE in your SELECT.
So in your case (ha, pun) (T-SQL Syntax):
SELECT
CASE
WHEN (YourDateFieldHere) < '04/01/2019' THEN (YourOutputFieldHere)
ELSE NULL
END (AS Alias)
FROM ...
CASE statements can check for multiple criteria, it doesn't have to just be one or the other, in this case just include more lines of WHEN (something) THEN (display this)
You can use case..when
( considering YYYYMMDD is the default format used in SAP at the internal level )
Select case when myDate >'20190104' then
null
else
T6.Segment2
end
as 'Old Department Code'
From yourTable

SQL CASE returning two values

I'm writing my first SQL CASE statement and I have done some research on them. Obviously the actual practice is going to be a little different than what I read because of context and things of that nature. I understand HOW they work. I am just having trouble forming mine correctly. Below is my draft of the SQL statement where I am trying to return two values (Either a code value from version A and it's title or a code value from version B and its title). I've been told that you can't return two values in one CASE statment, but I can't figure out how to rewrite this SQL statement to give me all the values that I need. Is there a way to use a CASE within a CASE (as in a CASE statement for each column)?
P.S. When pasting the code I removed the aliases just to make it more concise for the post
SELECT
CASE
WHEN codeVersion = A THEN ACode, Title
ELSE BCode, Title
END
FROM Code.CodeRef
WHERE ACode=#useCode OR BCode=#useCode
A case statement can only return one value. You can easily write what you want as:
SELECT (CASE WHEN codeVersion = 'A' THEN ACode
ELSE BCode
END) as Code, Title
FROM Code.CodeRef
WHERE #useCode in (ACode, BCode);
A case statement can only return a single column. In your scenario, that's all that is needed, as title is used in either outcome:
SELECT
CASE
WHEN codeVersion = "A" THEN ACode,
ELSE BCode
END as Code,
Title
FROM Code.CodeRef
WHERE ACode=#useCode OR BCode=#useCode
If you actually did need to apply the case logic to more than one column, then you'd need to repeat it.
Here is what I normally use:
SELECT
CASE
WHEN codeVersion = "A" THEN 'ACode'
WHEN codeVersion = "B" THEN 'BCode'
ELSE 'Invalid Version'
END as 'Version',
Title
FROM Code.CodeRef
WHERE
CASE
WHEN codeVersion = "A" THEN ACode
WHEN codeVersion = "B" THEN BCode
ELSE 'Invalid Version'
END = 'Acode'
my suggestion uses an alias. note on aliases: unfortunately you can't use the alias 'Version' in a where/group by clause. You have to use the whole case statement again. I believe you can only use an alias in an Order By.

how can I replace blank value with zero in MS-Acess

I have below query in Ms-Access but I want to replace Blank value with zero but I can't get proper answer. Is there any way to replace blank value in zero.
(SELECT
SUM(IIF(Review.TotalPrincipalPayments,0,Review.TotalPrincipalPayments))+
SUM(IIF(Review.TotalInterestPayments,0,Review.TotalInterestPayments ))
FROM
tblReviewScalars as Review
INNER JOIN tblReportVectors AS Report ON(Review.LoanID=Report.LoanID)
WHERE Report.AP_Indicator="A" AND Report.CashFlowDate=#6/5/2011# AND Review.AsofDate=#6/5/2011# AND ( Review.CreditRating =ReviewMain.CreditRating)) AS [Cash Collected During the Period],
I assume TotalPrincipalPayments and TotalInterestPayments are both numeric types, hence the 'blanks' in question is the NULL value.
In SQL, the set function SUM will disregard NULL values, unless all values resolve to NULL in which case NULL is returned (erroneously and the error is with SQL not Access for a change :)
To use a simple example, SELECT SUM(a) FROM T; will only return NULL when a IS NULL is TRUE for all rows of T or when T is empty. Therefore, you can move the 'replace NULL with zero' logic outside of the SUM() function. Noting that "NULLs propagate" in calculations, you will need to handle NULL for each SUM().
You haven't posted the whole of your query e.g. the source of the correlation name ('table alias') ReviewMain is not showm. But it seems clear you are constructing a derived table named "Cash Collected During the Period", in which case your calculated column needs an AS clause ('column alias') such as TotalPayments e.g.
...
(
SELECT IIF(SUM(Review.TotalPrincipalPayments) IS NULL, 0, SUM(Review.TotalPrincipalPayments))
+ IIF(SUM(Review.TotalInterestPayments) IS NULL, 0, SUM(Review.TotalInterestPayments))
AS TotalPayments
FROM tblReviewScalars as Review
INNER JOIN tblReportVectors AS Report
ON Review.LoanID = Report.LoanID
WHERE Report.AP_Indicator = 'A'
AND Report.CashFlowDate = #2011-05-06#
AND Review.AsofDate = #2011-05-06#
AND Review.CreditRating = ReviewMain.CreditRating
) AS [Cash Collected During the Period], ...
An alternative to #onedaywhen's answer is to use the nz function, which is specifically for null-substitution:
SELECT
SUM(NZ(Review.TotalPrincipalPayments,0))+
SUM(NZ(Review.TotalInterestPayments,0))
...
As onedaywhen pointed out, this is functionally equivalent to putting the function outside the aggregate, which may perform better (the function is called once, rather than once per un-aggregated row):
SELECT
NZ(SUM(Review.TotalPrincipalPayments),0)+
NZ(SUM(Review.TotalInterestPayments),0)
...
To change a null value to a zero in an Access 2010 database, open your table, go to design view, click on the field and set the default value to: =0.