How do I use concat and case switch together in PostgresSQL? - sql

I am trying to use concat as function and inside the same function use case switch statements in PostgresSQL. The end goal is populating a table with a bunch of statements that change according to the case.
Does anybody know how to solve this?
I tried to use '+' and ',' but I always get the same Syntax error
(SELECT concat(cast(idpersonale as varchar(5)),' = '
,case when dstitolo is not null then dstitolo else '' end + ' '
,case when dsnome is not null then dsnome else '' end + ' '
,case when dscognome is not null then dscognome else '' end
dscognome)
FROM global.glb_personale
WHERE cch.glb_personale.idpersonale =inter.interventoeseguitoda) as InterventoEseguitoDa
FROM cch.pats_cch_interventi inter
WHERE (idtiporecord is null or not idtiporecord in('uti','int')) and
NOT idintervento IN (SELECT idint
FROM cch.glo_error_data_2
WHERE (iddb = 'cch') AND (cnerror = 1))
order by idintervento;

Concatenation works with || operator or concat(text1, text2, text3, ...) function. Every text literal can be also an expression which gives a type text, like a CASE clause:
demo:db<>fiddle
SELECT
'you' || 'can' || 'concat' || 'like' || 'that' AS concat1,
concat('or', 'like', 'that') AS concat2,
concat('Mix' || 'both', 'up') AS concat3,
concat(
'And',
CASE WHEN false THEN 'now' ELSE 'doint' END || 'this',
CASE
WHEN true THEN 'with' || 'some'
WHEN false THEN 'CASE'
ELSE 'clauses'
END
) AS concat4
That means in your case: Change concat(text1 + text2 + text3) to concat(text1, text2, text3) (because the texts are function arguments) or to text1 || text2 || text3

since you are using concat(), replace + to , instead.
(SELECT concat(cast(idpersonale as varchar(5)),' = '
,case when dstitolo is not null then dstitolo else '' end, ' '
,case when dsnome is not null then dsnome else '' end, ' '
,case when dscognome is not null then dscognome else '' end
dscognome)
FROM global.glb_personale
WHERE cch.glb_personale.idpersonale =inter.interventoeseguitoda) as InterventoEseguitoDa
FROM cch.pats_cch_interventi inter
WHERE (idtiporecord is null or not idtiporecord in('uti','int')) and
NOT idintervento IN (SELECT idint
FROM cch.glo_error_data_2
WHERE (iddb = 'cch') AND (cnerror = 1))

While the concatenation operator (||) and the function (concat) combine strings there is a big difference between them: how they handle nulls.
If any operand is null then the concatenation operator result is NULL.
If any operand is null then the concatenation function moves to the next operand, leaving previous and subsequent results as they would had the null operand not been present. Example:
with dscognome (idpersonale,dstitolo ,dsnome ,dscognome) as
( values (1,'a','b','c')
, (2,'d','e',null)
, (3,'f',null,'g')
, (4,null, 'h', 'i')
, (5,null, null, null)
)
select idpersonale
, dstitolo || dsnome || dscognome "using || opreator"
, concat(dstitolo,dsnome,dscognome) "using concat function"
from dscognome;
Since the entire purpose of the case structure is to handle nulls, using the concatenation function entirely negates it's requirement and the query can be written:
with dscognome (idpersonale,dstitolo ,dsnome ,dscognome) as
( values (1,'a','b','c')
, (2,'d','e',null)
, (3,'f',null,'g')
, (4,null, 'h', 'i')
, (5,null, null, null)
)
SELECT concat(cast(idpersonale as varchar),' = '
, dstitolo , ' '
, dsnome, ' '
, dscognome )
from dscognome;

Related

using xmlagg to find count to concatenate

SELECT DISTINCT
ent.entity_key_id AS query1kid,
CAST(substr(rtrim(XMLAGG(xmlelement(e,alstd.relationship_desc
||
CASE
WHEN(alstd.joint_flag = 'No' AND ent.anonymous_flag = 'No') THEN ''
ELSE('('
||
CASE
WHEN alstd.joint_flag = 'Yes' THEN 'Joint'
ELSE ''
END
||
CASE
WHEN ent.anonymous_flag = 'Yes' THEN ',Anon'
ELSE ''
END
|| ')')
END
|| ': '
|| allocthm.allocation_description
|| '('
|| substr(allocthm.allocation_code,5,6) || ***count(ben.entity_key_ID)***
|| ')',',').extract('//text()')
ORDER BY
ent.entity_key_id
).getclobval(),','),1,4000) AS VARCHAR(4000) ) AS displayfiled1
FROM
er_datamart.allocation_theme allocthm
left JOIN er_datamart.allocation_stewardee alstd ON (allocthm.allocation_code = alstd.allocation_code and alstd.status_code <> 'F')
INNER JOIN er_datamart.entity_d ent ON alstd.entity_key_id = ent.entity_key_id
LEFT OUTER JOIN ER_DATAMART.ALLOCATION_BENEFICIARY ben ON ben.allocation_code = allocthm.allocation_code
GROUP BY
ent.entity_key_id
This gives me an error:
ORA-00937: not a single-group group function
I'm trying to find the count(ben.entity_key_ID) so that I can have it appended to my already functional query. Any help would be appreciated.
The problem seems to be the count() inside the xmlagg() - you have nested group functions that the group-by clause can't handle.
You can move the string concatenation into an inline view with its own group-by to get that count, and then perform the XML aggregation from that; something like:
SELECT
entity_key_id AS query1kid,
CAST(substr(rtrim(
XMLAGG(xmlelement(e, constructed_string, ',').extract('//text()')
ORDER BY entity_key_id
).getclobval(),','),1,4000) AS VARCHAR(4000) ) AS displayfiled1
FROM (
SELECT ent.entity_key_id,
alstd.relationship_desc
||
CASE
WHEN(alstd.joint_flag = 'No' AND ent.anonymous_flag = 'No') THEN ''
ELSE('('
||
CASE
WHEN alstd.joint_flag = 'Yes' THEN 'Joint'
ELSE ''
END
||
CASE
WHEN ent.anonymous_flag = 'Yes' THEN ',Anon'
ELSE ''
END
|| ')')
END
|| ': '
|| allocthm.allocation_description
|| '('
|| substr(allocthm.allocation_code,5,6) || count(ben.entity_key_ID)
|| ')' as constructed_string
FROM
allocation_theme allocthm
LEFT JOIN allocation_stewardee alstd
ON allocthm.allocation_code = alstd.allocation_code and alstd.status_code <> 'F'
INNER JOIN entity_d ent
ON alstd.entity_key_id = ent.entity_key_id
LEFT OUTER JOIN ALLOCATION_BENEFICIARY ben
ON ben.allocation_code = allocthm.allocation_code
GROUP BY
ent.entity_key_id,
alstd.relationship_desc,
alstd.joint_flag,
ent.anonymous_flag,
allocthm.allocation_description,
allocthm.allocation_code
)
GROUP BY
entity_key_id
The ELSE '' parts are redundant as that is the default behaviour but you might prefer to keep them for clarity/explicitness. Your joint/anon part might need a bit more work - if joint is No and anon is Yes you get (,Anon) - I think - which looks a bit odd, but might be what you need.

Pass column name as a parameter

I need to pass a column name from front end to back end in my code. i'm using c# with oracle and when i pass the column name as a parameter, it gives an error and it's because the column name is used as a string in here and i need to know how to fix this. here is my code,
PROCEDURE PR_GETCLIENTCONTRACTDATA(INSTRFIELD IN VARCHAR2,INSTRCONTRACTNO IN VARCHAR2,CUR_OUTPUT OUT T_CURSOR)--ADDED BY DIDULA 25/10/2017
IS
BEGIN
OPEN CUR_OUTPUT FOR
SELECT c.con_no,
DECODE (a.clm_cori,
'1', a.clm_cltitle || ' ' || a.clm_initialsfull || ' '
|| a.clm_name,
a.clm_name
) cliname,
a.clm_code,
( a.clm_permaddline1
|| '|'
|| a.clm_permaddline2
|| '|'
|| COALESCE (a.clm_permaddline3, a.clm_permaddline4)
|| '|'
|| NULLIF ((a.clm_permaddline4),
COALESCE (a.clm_permaddline3, a.clm_permaddline4)
)
) address
FROM leaseinfo.tblcontracts c, corpinfo.tblclientmain a
WHERE a.clm_code = c.con_clmcode
AND INSTRFIELD = INSTRCONTRACTNO; ***here INSTRFIELD is the column name
that i need to pass***
END PR_GETCLIENTCONTRACTDATA;
Whitelist the column names:
PROCEDURE PR_GETCLIENTCONTRACTDATA(
INSTRFIELD IN VARCHAR2,
INSTRCONTRACTNO IN VARCHAR2,
CUR_OUTPUT OUT T_CURSOR
)
IS
BEGIN
OPEN CUR_OUTPUT FOR
SELECT -- your select clauses
FROM leaseinfo.tblcontracts c,
INNER JOIN corpinfo.tblclientmain a -- ANSI join syntax
ON a.clm_code = c.con_clmcode
WHERE CASE INSTRFIELD
WHEN 'COLUMNA' THEN ColumnA
WHEN 'COLUMNB' THEN ColumnB
WHEN 'COLUMNC' THEN ColumnC
END = INSTRCONTRACTNO;
END PR_GETCLIENTCONTRACTDATA;
/
When you use OPEN cur FOR ... you can pass a string, i.e.
PROCEDURE PR_GETCLIENTCONTRACTDATA(INSTRFIELD IN VARCHAR2,INSTRCONTRACTNO IN VARCHAR2,CUR_OUTPUT OUT T_CURSOR)
IS
BEGIN
OPEN CUR_OUTPUT FOR
'SELECT c.con_no,
DECODE (a.clm_cori,
''1'', a.clm_cltitle || '' '' || a.clm_initialsfull || '' ''
|| a.clm_name,
a.clm_name
) cliname,
a.clm_code,
( a.clm_permaddline1
|| ''|''
|| a.clm_permaddline2
|| ''|''
|| COALESCE (a.clm_permaddline3, a.clm_permaddline4)
|| ''|''
|| NULLIF ((a.clm_permaddline4),
COALESCE (a.clm_permaddline3, a.clm_permaddline4)
)
) address
FROM leaseinfo.tblcontracts c
JOIN corpinfo.tblclientmain a ON a.clm_code = c.con_clmcode
WHERE '||DBMS_ASSERT.SIMPLE_SQL_NAME(INSTRFIELD)||' = :INSTRCONTRACTNO)'
USING INSTRCONTRACTNO;
END PR_GETCLIENTCONTRACTDATA;

SQL Server stored proc substitute an empty string if column is empty or null

I need to check to see if a certain coloumn in my stored proc is either empty or null.
This is a snippet of what I have right now:
SELECT * ,
CASE WHEN a.USER IS NULL
THEN b.ROLE
ELSE ISNULL(a.FirstName,'') + ' ' + (ISNULL(a.MiddleName+' ','') + ISNULL(a.LastName,'')
END AS 'CustomerName'
I am checking to see if a.MiddleName is NULL but how do I also check to see if its empty and if its empty to just insert a empty string (no space)?
Thanks
Change to
SELECT
* ,
CASE
WHEN a.USER IS NULL
THEN b.ROLE
ELSE CASE
WHEN ISNULL(a.MiddleName, '') = ''
THEN ISNULL(a.FirstName,'') + ' ' + ISNULL(a.LastName,'')
ELSE ISNULL(a.FirstName,'') + ' ' + a.MiddleName + ' ' + ISNULL(a.LastName,'')
END
END AS 'CustomerName'
Another sollution is:
SELECT * ,
CASE WHEN a.USER IS NULL
THEN b.ROLE
ELSE ISNULL(a.FirstName,'') + replace( ( ' ' + ISNULL(a.MiddleName+' ',' '),' ',' ') + ISNULL(a.LastName,'')
END AS 'CustomerName'

Invalid column names ERROR

i have a simple query below. but I don't know why I am getting an invalid column names error for field names and error value in where clause.
select * From (
select [SubscriberDataId]
,Case When ISNUMERIC([SubscriberCode]) = 0 Then cast([SubscriberCode]as varchar(9)) Else '~' end as [SubscriberCode]
,Case When ISDATE([Dob]) = 0 Then Cast([Dob] as Varchar(9)) Else '~' end as [Dob]
,Case When ISNUMERIC([FacetsGroup]) = 0 Then cast([FacetsGroup]as varchar(9)) Else '~' end as [FacetsGroup]
from Facets.SubscriberData) [sd]
Unpivot
(ErrorValue for FieldName in ([SubscriberCode],
[Dob],[FacetsGroup])) as x
where x.ErrorValue <> '~' and
NOT EXISTS (SELECT *
FROM Elig.dbo.ErrorTable
WHERE TableName = facets.SubscriberData
AND FieldName IN( [x].[SubscriberCode],[x].[Dob],[x].[FacetsGroup])
AND ErrorValue IN( [SubscriberCode],[Dob],[FacetsGroup]))
try
select * From
(select [SubscriberDataId],
Case When ISNUMERIC([SubscriberCode]) = 0
Then cast([SubscriberCode]as varchar(9))
Else '~' end as [SubscriberCode],
Case When ISDATE([Dob]) = 0
Then Cast([Dob] as Varchar(9))
Else '~' end as [Dob],
Case When ISNUMERIC([FacetsGroup]) = 0
Then cast([FacetsGroup]as varchar(9))
Else '~' end as [FacetsGroup]
from Facets.SubscriberData) [sd]
Unpivot (ErrorValue for FieldName in ([SubscriberCode], [Dob],[FacetsGroup])) as x where x.ErrorValue <> '~'
and NOT EXISTS (SELECT * FROM Elig.dbo.ErrorTable
WHERE TableName = facets.SubscriberData
AND FieldName IN( '[x].[SubscriberCode]','[x].[Dob]','[x].[FacetsGroup]')
AND ErrorValue IN( '[SubscriberCode]','[Dob]','[FacetsGroup]'))

T SQL Conditional String Concatenation

Have a 5 columns of address data. I need to concatenate these fields into a single address with spaces in between the values if they exist. If the column has a null value I should skip it and not enter any space.
select
case
when street_number != '' THEN (cast(street_number as int))
end as street_number,
case
when street_ext != '' then
case
when street_ext = 50 then '1/2'
end
end as street_ext,
case
when street_direct ! = '' then street_direct
end as street_direct,
case
when site_street ! = '' then site_street
end as site_street,
case
when site_address ! = '' then site_address
end as site_address
from parcel
what I'd like to do is have a variable and assign it to the value of the first column street_number, then when I move on to the next column, street_ext, if it isn't null I'd like to check to see if the variable is null and if not, append a space and the value...and so on down the road.
I'm rusty as hell and could use a push in the right direction.
Thanks everyone.
Use the "+" to concatenate strings in TSQL:
SELECT CASE
WHEN LEN(p.street_number) > 0 THEN p.street_number + ' '
ELSE ''
END +
CASE
WHEN p.street_ext = 50 THEN '1/2'
WHEN LEN(p.street_ext) > 0 THEN ''
ELSE p.street_ext
END + ' ' +
CASE
WHEN LEN(p.street_direct) > 0 THEN p.street_direct + ' '
ELSE ''
END +
CASE
WHEN LEN(p.site_street) > 0 THEN p.site_street + ' '
ELSE ''
END +
CASE
WHEN LEN(p.site_address) > 0 THEN p.site_address + ' '
ELSE ''
END AS full_address
FROM PARCEL p
The LEN function returns zero if the string value is NULL, or a zero length string.
Nested isnulls could do what you need. Something like:
SELECT
ISNULL(streetnumber + ' ', '')
+ ISNULL(streetext + ' ', '')
etc
relying on the fact that NULL + ' ' = NULL.
Something along the lines of:
select coalesce(street_number+' ','')+
coalesce(case when street_ext=50 then '1/2' else null end+' ','')+
coalesce(street_direct+' ','')+
coalesce(site_street+' ','')+
coalesce(site_address,'')
from parcel
I have assumed your data types are all varchar or similar for simplicity. If you are OK with removing any double spaces, how about:
rtrim(ltrim(replace(isnull(street_number) + ' '
+ isnull(street_ext) + ' '
+ isnull(street_direct) + ' '
+ isnull(site_street) + ' '
+ isnull(site_address), ' ', ' ')))
First I would declare the seperator as a variable, because customers are notorious for changing these.
I would do this as follows:
DECLARE #AddressSeperator NVARCHAR(5) = ' '
...and then for the column declation, I'd use the following:
, CONCAT
(
(CASE WHEN LEN(p.street_number) > 0 THEN p.street_number + #AddressSeperator ELSE '' END)
, (CASE WHEN p.street_ext = 50 THEN '1/2' + #AddressSeperator WHEN LEN(p.street_ext) > 0 THEN p.street_ext + #AddressSeperator ELSE '' END)
, (CASE WHEN LEN(p.street_direct) > 0 THEN p.street_direct + #AddressSeperator ELSE '' END)
, (CASE WHEN LEN(p.site_street) > 0 THEN p.site_street + #AddressSeperator ELSE '' END)
, ISNULL(p.site_address, '')
) AS [full_address]