SQL Dynamic column value allocation from column name reference - sql

Input table looks as below which has various conversions, but reported only on one conversion (defined in report_field)
Output table has reported_conversion which is derived based on report_field
What's the best way of coding to achieve this?

CASE expression could be used:
SELECT *
,CASE report_field
WHEN 'conversion1' THEN conversion1
WHEN 'conversion2' THEN conversion2
WHEN 'conversion3' THEN conversion3
END AS reported_conversion
FROM tab;
or DECODE
SELECT *, DECODE(report_field,
'conversion1', conversion1
'conversion2', conversion2
'conversion3', conversion3)
FROM tab

Related

Dealing with null in a case statement on a casted value in big query

I want to group a value which is astring of decimals into named groups.
Example :
CASE WHEN CAST(X as NUMERIC)<1000 THEN "Under1000" ELSE "Over1000" END
As I've got some values missing, I would rather use safe_cast instead of cast and want a specific group for missing values.
I could go for :
CASE WHEN SAFE_CAST(X as NUMERIC) = NULL THEN "MissingData" WHEN SAFE_CAST(X as NUMERIC)<1000 THEN "Under1000" ELSE "Over1000" END
But what annoys me here is that I'm reapeating the safe_cast operation.
Is there a way to avoid that ?
I've been reading following example :
CASE operation(X) WHEN result1 THEN "result1" WHEN result2 THEN "result2" ELSE "other_result" END
But that kind of syntax seems to work only for equality operator in the when statements (ie operation(X) = result1 or operation(X) = result2 etc.).
And here I use inferior (or superior)... So I don't know how to manage that.
I guess there must be a way to avoid that operation repetition but can't figure out how.
Thanks for your help.
This should help you to avoid writing SAFE_CAST() several times:
WITH your_data AS (
SELECT "Bob" as name, "150.19" as weight UNION ALL
SELECT "Tom", "2000.90" UNION ALL
SELECT "Jerry", Null)
, transform as (
SELECT name, CAST(weight as NUMERIC) as weight
FROM your_data
)
SELECT
name,
CASE
WHEN weight IS NULL
THEN "MissingData"
WHEN weight<1000
THEN "Under1000"
ELSE "Over1000"
END as weight_agg
FROM transform
Results:
Not sure there is a syntax-based answer that would help, but one potential way to achieve "cleaner" or non-repetitive code is break up your query into logical chunks using CTEs.
with data as (), -- raw data
casted as (), -- do your safe_cast here
transformed as () - do your case statement here
select * from transformed
It does make for "longer" code, but it also allows for cleaner logic in the transformation stage (your stated goal).

Getting an error when using CONCAT in BigQuery

I'm trying to run a query where I combine two columns and separate them with an x in between.
I'm also trying to get some other columns from the same table. However, I get the following error.
Error: No matching signature for function CONCAT for argument types: FLOAT64, FLOAT64. Supported signatures: CONCAT(STRING, [STRING, ...]); CONCAT(BYTES, [BYTES, ...]).
Here is my code:
SELECT
CONCAT(right,'x',left),
position,
numbercreated,
Madefrom
FROM
table
WHERE
Date = "2018-10-07%"
I have tried also putting a cast before but that did not work.
SELECT Concast(cast(right,'x',left)), position,...
SELECT Concast(cast(right,'x',left)as STRING), position,...
Why am I getting this error?
Are there any fixes?
Thanks for the help.
You need to cast each value before the concat():
SELECT CONCAT(CAST(right as string), 'x', CAST(left as string)),
position, numbercreated, Madefrom
FROM table
WHERE Date = '2018-10-07%';
If you want a particular format, then use the FORMAT() function.
I also doubt that your WHERE will match anything. If Date is a string, then you probably want LIKE:
WHERE Date LIKE '2018-10-07%';
More likely, you should use the DATE function or direct comparison:
WHERE DATE(Date) = '2018-10-07'
or:
WHERE Date >= '2018-10-07' AND
Date < '2018-10-08'
Another option to fix your issue with CONCAT is to use FROMAT function as in below example
#standardSQL
WITH `project.dataset.table` AS (
SELECT 1.01 AS `right`, 2.0 AS `left`
)
SELECT FORMAT('%g%s%g', t.right, 'x', t.left)
FROM `project.dataset.table` t
result will be
Row f0_
1 1.01x2
Note: in above specific example - you could use even simpler statement
FORMAT('%gx%g', t.right, t.left)
You can see more for supporting formats
Few recommendations - try not to use keywords as a column names/aliases. If for some reason you do use - wrap such with backtick or prefix it with table name/alias
Yet another comment - looks like you switched your values positions - your right one is on left side and left one is on right - might be exactly what you need but wanted to mention
Try like below by using safe_cast:
SELECT
CONCAT(SAFE_CAST( right as string ),'x',SAFE_CAST(left as string)),
position,
numbercreated,
Madefrom
FROM
table
WHERE
Date = '2018-10-07'

How to convert this SAS code to SQL Server code?

SAS CODE:
data table1;
set table2;
_sep1 = findc(policynum,'/&,');
_count1 = countc(policynum,'/&,');
_sep2 = findc(policynum,'-');
_count2 = countc(policynum,'-');
_sep3 = findc(policynum,'_*');
_count3 = countc(policynum,'_*');
How can I convert this into a select statement like below:
select
*,
/*Code converted to SQL from above*/
from table2
For example I tried the below code:
select
*,
charindex('/&,',policynum) as _sep1,
LEN(policynum) - LEN(REPLACE(policynum,'/&,','')) as _count1
from table2
But I got a ERROR 42S02: Function 'CHARINDEX(UNKNOWN, VARCHAR)' does not exist. Unable to identify a function that satisfies that given argument types. You may need to add explicit typecasts.
Please note that the variable pol_no is: 'character varying(50) not null'.
I am running this on using Aginity Workbench for Netezza. I believe this is IBM.
Assuming Oracle based on CHARINDEX() this may work:
You need to apply it twice, once for each character and take the minimum to find the first occurrence.
There may be a better suited function within Oracle, but I don't know enough to suggest one.
select
*,
min(charindex('/',policynum), charindex('&', policynum)) as _sep1
from table2
EDIT: based on OP notes.
Netezza seems like IBM which means use the INSTR function, not CHARINDEX.
select
*,
min(instr(policynum, '/'), instr(policynum, '&')) as _sep1
from table2
https://www.ibm.com/support/knowledgecenter/en/SSGU8G_12.1.0/com.ibm.sqls.doc/ids_sqs_2336.htm
FINDC & COUNTC functions are basically used for searching a character & counting them.
You can use LIKE operator from SQL to find characters with '%' and '_' wildcards
e.g. -
SELECT * FROM <table_name> WHERE <column_name> LIKE '%-%';
and
SELECT COUNT(*) FROM <table_name> WHERE <column_name> LIKE '%-%';
You can use regular expressions in the LIKE operator as well

Adding a "calculated field" in bigquery

I have a raw table in bigquery, and I want to add a "conditional"/"calculated" column based on a given value, saying something like:
CASE
WHEN `columnA`="valueX" THEN `columnB`
ELSE NULL
AS `valueX`
The problem is that I can't just say SELECT *, CASE..., since then I must do GROUP BY over all of the columns.
Is there a simple way to create a "calculated" column like that ? Maybe using some UDF and views "tricks" ?
Input example:
Output example:
Thanks In advance,
Shushu
SELECT *,
CASE
WHEN columnA='valueX' THEN columnB
ELSE NULL
END AS valueX
FROM

How to use function in subquery

I have one table named MemberCheque where the fields are:
MemberName, Amount
I want to to show the name and the respective amount in numbers and as well as in words after separating the integer amount from the decimal. So my query is like:
SELECT MemName, Amount, (SELECT (Amount)%1*100 AS lefAmn, dbo.fnNumberToWords(lefAmn)+
'Hundred ', (Amount) - (Amount)%1 AS righAmnt, dbo.fnNumberToWords (righAmnt)+' Cents'
from MemberCheque) AS AmountInWords FROM MemberCheque
but my store procedure can take only integer value to change into words. So, I am doing separating the Amount into two parts before and after decimal but when I am trying to run this query it gives me error that lefAmn and righAmnt is not recognised. Because I am trying to send the parameter from the same query.
The first problem is that you have a subquery that is returning more than one value, and that is not allowed for a subquery in the select clause.
That answer to your specific question is to use cast() (or convert()) to make the numbers integers:
select leftAmt, rightAmt,
(dbo.fnNumberToWords(cast(leftAmt as int))+'Hundred ' +
dbo.fnNumberToWords(cast(rightAmt as int))+' Cents'
) as AmountInWords
from (SELECT (Amount%1)*100 AS leftAmt,
(Amount) - (Amount)%1 AS rightAmt
from MemberCheque
) mc
If you can't alter your function, then CAST the left/right values as INT:
CAST((Amount)%1*100 AS INT) AS lefAmn
CAST((Amount) - (Amount)%1 AS INT) AS righAmnt
You can't pass the alias created in the same statement as your function parameter, you need:
dbo.fnNumberToWords (CAST((Amount)%1*100 AS INT))
dbo.fnNumberToWords (CAST((Amount) - (Amount)%1 AS INT))