How to put two simple expressions together? - sql-server

I'm working on a simple SSIS package for myself; I'm a newbie to all of this.
I have a flat file that has MALE or FEMALE values for Gender.
I want this to be only M or F in the Gender column on SQL Server when I load it. I have the below expressions:
REPLACE ( [Gender], "Female", "F")
REPLACE ( [Gender], "Male", "M")
I'm not sure how to club them together.
Any help/tips would be highly appreciated.
Thank you!

Chain them:
REPLACE (REPLACE ( [Gender], "Female", "F" ), "Male", "M")
Breaking it down, the inner REPLACE replaces all instances of "Female" with "F" but does nothing to any other values. The output of that function call ( which should either be "F" or "Male") is then passed to the outer REPLACE which transforms "Male" to "M". So, you should get "M" or "F" as appropriate.

Try CASE instead:
CASE
WHEN [Gender] = 'Female' THEN 'F'
WHEN [Gender] = 'Male' THEN 'M'
ELSE NULL
END

Use a derived column -
If the allowable values for that column are only Male and Female then this expression would suffice- ([Gender]=="Male"?"M":"F")
In case the column holds values other than Male/Female you might want to do something additional, here I am just passing the [Gender] value as is if it does not fall into Male/Female - ([Gender]=="Male"?"M":([Gender] == "Female"? "F":[Gender]))

Related

Replacing elements in an array column in snowflake

I have sample data as follows;
team_id
mode
123
[1,2]
Here mode is an array.The goal is to replace the values in column mode by literal values, such as 1 stands for Ocean, and 2 stands for Air
Expected Output
team_id
mode
123
[Ocean,Air]
Present Approach
As an attempt, I tried to first flatten the data into multiple rows;
team_id
mode
123
1
123
2
Then we can define a new column assigning literal values to mode column using a case statement, followed by aggregating the values into an array to get desired output.
Can I get some help here to do the replacement directly in the array? Thanks in advance.
Using FLATTEN and ARRAY_AGG:
CREATE OR REPLACE TABLE tab(team_id INT, mode ARRAY) AS SELECT 123, [1,2];
SELECT TEAM_ID,
ARRAY_AGG(CASE f.value::TEXT
WHEN 1 THEN 'Ocean'
WHEN 2 THEN 'Air'
ELSE 'Unknown'
END) WITHIN GROUP(ORDER BY f.index) AS new_mode
FROM tab
,LATERAL FLATTEN(tab.mode) AS f
GROUP BY TEAM_ID;
Output:
TEAM_ID
NEW_MODE
123
[ "Ocean", "Air" ]
For an alternative solution with easy array manipulation. you could create a JS UDF:
create or replace function replace_vals_in_array(A variant)
returns variant
language javascript
as $$
dict = {1:'a', 2:'b', 3:'c', 4:'d'};
return A.map(x => dict[x]);
$$;
Then to update your table:
update arrs
set arr = replace_vals_in_array(arr);
Example setup:
create or replace temp table arrs as (
select 1 id, [1,2,3] arr
union all select 2, [2,4]
);
select *, replace_vals_in_array(arr)
from arrs;

Field formula with Case/If statement

I want to set a formula for a field C by check two picklist fields A and B (the value in the picklist will Yes, No, None)
If field A = "Yes" and field B = "Yes" then field C = "1"
If field A = "Yes" and field B <> "Yes" then field C = "2"
If field A <> "Yes" and field B = "Yes" then field C = "3"
If field A <> "Yes" and field B <> "Yes" then field C = "4"
I don't know how to set a formula for field C to make it works, I try CASE, IF statement without any luck.
Any help will be appreciated.
Thanks,
I would suggest to spend some times on these trailhead: Use Formula Fields and Advanced Formulas.
Bookmarking Formula Operators and Functions documentation page would be useful too.
Since A and B are picklist fields you must use ISPICKVAL(field, value).
If C is a text formula field:
IF( ISPICKVAL(A, 'Yes'),
IF ( ISPICKVAL(B, 'Yes'),
'1',
'2'
),
IF ( ISPICKVAL(B, 'Yes'),
'3',
'4'
)
)

Naming items in Value clause for readability

Is there a better way to achieve mapping items in the values to column names. I always do this using comments:
insert into Table1 (Col1, Col2, ..., Coln)
values ('One' /* Col1 */, 'Two' /* Col2 */, ..., 'ValN' /* Coln */);
It becomes especially important when there are many columns involved and the values clause has queries in it. I always have to count and see which item in the values clause is for which column. Therefore, I just use comments as shown above. I will state the obvious that sometimes depending on the query, I may keep them on separate lines.
Any other way?
Yours is a good way. I usually use one line for each column. It can get really long but I find it more readable. Something like this:
insert into Table1 (
Col1
,Col2
,...
,Coln
)
values (
One /* Col1 */
,Two /* Col2 */
,...
,ValN /* Coln */
);
In some cases, using a JSON string could be useful. In other cases it maybe an overkill. Here's a simple example:
Let's say we have a table called "test" with two columns: "Number" (INT) and "Word" (VARCHAR(40))
We can insert records in that table using the following construction:
INSERT INTO test (Number, Word)
SELECT source.Number, source.Word
FROM
(
SELECT Number, Word
FROM
OpenJson('[{
"number": 01, "word": "This"
}, {
"number": 02, "word": "Is"
}, {
"number": 03, "word": "Just"
}, {
"number": 04, "word": "a"
}, {
"number": 05, "word": "Test"
}] '
) WITH (Number INT '$.number', Word VARCHAR(40) '$.word')
) AS source
As we can see:
The data to insert is stored inside the JSON string. We then name the each property in the JSON string using the same column names in the table.
When doing the actual insert, the names of the values to insert are variables that have the same name than their columns, making it very readable. (source.Number, source.Word).
In some cases, using the JSON string can help out not only with the mapping of the data and their columns but also debugging the data and finding wrong values.

Check if value exists in postgres array for partitioning via check constraint

I found this very similar question but all of the answer started with a 'select' statement. I want to check whether a string is contained in a constant array with about 30 other strings. I could write a long x == a OR x == b OR... statement but I thought there might be a cleaner way.
So this doesn't work as a constraint check: SELECT language = ANY ('{"en", "pt", "es", "fr"}'::text[])
Just removing the SELECT works:
CHECK(
language = ANY ('{"en", "pt", "es", "fr"}'::text[])
)
But as a_horse_with_no_name pointed out:
Not using an array is even better, as this does not break the partitioning optimization.
CHECK(
not( language in ('en', 'pt', 'es'))
)
Now SELECT * FROM myTable WHERE language='de'; will not even look at this table.

T-SQL field parsing

There is a field in a 3rd party database that I need to group on for a report I'm writing. The field can contain a few different types of data. First it could contain a 3 digit number. I need to break these out into groups such as 101 to 200 and 201 to 300. In addition to this the field could also be prefaced with a particular letter such a M or K then a few numbers. It is defined as VARCHAR(8) and any help in how I could handle both cases where it may start with a particular letter or fall within a numeric range would be appreciated. If I could write it as a case statement and return a department based either on the numeric value or the first letter that would be the best so I can group in my report.
Thanks,
Steven
If I could write it as a case statement and return a department based either on the numeric value or the first letter that would be the best so I can group in my report.
case when substring( field, 1, 1 ) = 'M' then ...
when substring( field, 1, 1 ) = 'K" then ...
else floor( (cast( field as int) - 1 ) / 100) end
select ....
group by
case when substring( field, 1, 1 ) = 'M' then ...
when substring( field, 1, 1 ) = 'K" then ...
else floor( (cast( field as int) - 1 ) / 100) end
Matt Hamilton asks,
Any reason why you've opted to use substring(field, 1, 1) rather than simply left(field, 1)? I notice that #jms did it too, in the other answer.
I know substring is specified in ANSI-92; I don't know that left is. And anyway, left isn't a primitive, as it can be written in terms of substring, so using substring seems a little cleaner.
select
CASE (CASE WHEN substring(field,1,1) between 0 and 9 then 'N' Else 'C' END)
WHEN 'N' THEN
CASE field
WHEN ... THEN ...
WHEN ... THEN ...
END
WHEN 'C' THEN
CASE field
WHEN ... THEN ...
WHEN ... THEN ...
END
END

Resources