How to concatenate cols under special rules? - sql

I want to select concatenated string, max 255 char. Original query, without shortenings, was:
SELECT
b.title
||
CASE
WHEN b.subtitle != '' THEN '. ' || b.subtitle
ELSE ''
END
||
CASE
WHEN b.cover = 'paperback' THEN ' P'
WHEN b.cover = 'hardcover' THEN ' K'
WHEN b.cover = 'spiral' THEN ' S'
ELSE ''
END
||
CASE
WHEN b.year > 0 THEN ' ' || b.year
ELSE ''
END
||
CASE
WHEN b.volume > 0 THEN ' ' || b.volume || '. osa'
ELSE ''
END
||
CASE
WHEN p.name != '' THEN ' ' || p.name
ELSE ''
END
AS name
FROM table b
JOIN table_p p
ON b.id = p.foreign_id;
Rule: concatenated string may be up to 255 chars
Prioritized fields:
b.title (text, up to 250 chars),
b.cover (2 chars),
b.year (4 char + space = 5),
b.volume (int<100 + additional string '. osa' = 7-8 chars).
Less important:
b.subtitle (text, up to 250 chars),
p.name (text, up to 150 chars )
All fields besides b.title may absent/be empty.
One approach I can think of: because three short mandatory fields (cover, year, volume) may be max 15 chars, everything other could be max 240 chars. Because p.name is not so important, I could concatenate and cut afterwards, if needed. So main objective with this approach: b.title + b.subtitle must fit into 240 chars. Looks like that:
SELECT
SUBSTR(
SUBSTR( b.title
||
CASE
WHEN b.subtitle != '' THEN '. ' || b.subtitle
ELSE ''
END,
0, 240 )
||
CASE
WHEN b.cover = 'paperback' THEN ' P'
WHEN b.cover = 'hardcover' THEN ' K'
WHEN b.cover = 'spiral' THEN ' S'
ELSE ''
END
||
CASE
WHEN b.year > 0 THEN ' ' || b.year
ELSE ''
END
||
CASE
WHEN b.volume > 0 THEN ' ' || b.volume || '. osa'
ELSE ''
END
||
CASE
WHEN p.name != '' THEN ' ' || p.name
ELSE ''
END,
0, 255 ) AS name
FROM table b
JOIN table_p p
ON b.id = p.foreign_id;
This approach is Ok-ish.
My question: is there better way to control every aspect of such concatenation?
I am using Postgresql 9.6

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.

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'

How to handle exception in listagg() function

I am using listagg in my script
listagg(' |' || aktiv.AKTIVITÄT_NR || ' |' || aktiv.AKTIVITÄT_KÜRZEL || ' |' || aktiv.AKTIVITÄT_BESCHREIBUNG || ' |' || aktiv.AKTIVITÄT_ERWARTETES_ERGEBNIS|| ' |' || CHR(10)) within group (order by aktiv.AKTIVITÄT_NR)) as activity
When listagg exceed 4000 bytes all script fail. How can I handle exception and for this record insert e.x. NULL and go to the next record without fail.
Sorry, I use my own example to show the idea, because I simply have no German layout and your tables as well:
with src as (/* overflow */
select 1 id, level lv
from dual
connect by level <= 10000
union all
/* fitting */
select 2, level lv
from dual
connect by level <= 10
union all
select 3, level lv
from dual
connect by level <= 5)
select listagg(case when length_ <= 4000 then lv end,',') within group (order by lv)
from (select id,lv,sum(length(lv) + 1) over (partition by id) - 1 length_ from src)
group by id
The idea:
src is your table, id is the value you are grouping by, level is your value
this subquery select id,lv,sum(length(lv) + 1) over (partition by id) - 1 length_ from src gathers the future length of listagg result, + 1 is made for delimeter ',', - 1 is done for the last delimeter which is not used
expression listagg(case when length_ <= 4000 then lv end,',') within group (order by lv) checks if the length is less than allowed value (4000), if it is overflown it returns null
I hope this solves your problem.
I think you should count SUM of LENGTH of strings for each group. And then use CASE to handle if this sum length > 4000. In the following query I join original table and a table with SUM(LENGTH) for each group. Try this:
select t.id,
CASE WHEN (TL.SumLen<=4000)
THEN LISTAGG(t.Str,',')
WITHIN GROUP (ORDER BY Str)
OVER (PARTITION BY t.ID)
ELSE NULL
END
FROM t
JOIN
(
SELECT Id, SUM(LENGTH(str||',')) SumLen
FROM t
GROUP BY ID
) TL on T.id=TL.id
SQLFiddle demo
#Simon : here is the code
drop table Project.Iterations;
drop table Project.test_steps;
CREATE TABLE Project.TEST_STEPS
(
test_case_id NUMBER(9,0),
test_step varchar2(4000)
);
CREATE TABLE Project.TEST_CASES_WITHOUT_TEST_STEPS
(
test_case_id NUMBER(9,0)
);
INSERT INTO Project.TEST_STEPS(test_case_id,test_step)
select test_case_id ,
listagg(activity, chr(10)) within group (order by header1 ) as test_step
from(
select
testschrit.testfall_id as test_case_id,
'h2.' || TESTSCHRITT_NR || ' ' || CAST(TESTSCHRITT_BEZEICHNUNG AS varchar(600)) || CHR(10) || CAST(TESTSCHRITT_BESCHREIBUNG AS varchar(600)) as header1,
('h2.' || TESTSCHRITT_NR || ' ' || CAST(TESTSCHRITT_BEZEICHNUNG AS varchar(600)) || CHR(10) || CAST(TESTSCHRITT_BESCHREIBUNG AS varchar(600))
|| '||AKTIVITÄT_NR' || '||AKTIVITÄT_KÜRZEL' || '||AKTIVITÄT_BESCHREIBUNG' || '||AKTIVITÄT_ERWARTETES_ERGEBNIS||' || CHR(10)
/*|| clobagg(' |' || aktiv.AKTIVITÄT_NR || ' |' || aktiv.AKTIVITÄT_KÜRZEL || ' |' || aktiv.AKTIVITÄT_BESCHREIBUNG || ' |' || aktiv.AKTIVITÄT_ERWARTETES_ERGEBNIS|| ' |' || CHR(10)) as activity*/
|| listagg(' |' || aktiv.AKTIVITÄT_NR || ' |' || aktiv.AKTIVITÄT_KÜRZEL || ' |' || aktiv.AKTIVITÄT_BESCHREIBUNG || ' |' || aktiv.AKTIVITÄT_ERWARTETES_ERGEBNIS|| ' |' || CHR(10)) within group (order by aktiv.AKTIVITÄT_NR)) as activity
FROM Project.TESTFALLBESCHREIBUNG tfb, Project.TESTSCHRITTE testschrit, Project.AKTIVITÄTEN aktiv
WHERE testschrit.testfall_id = tfb.testfall_id(+)
AND testschrit.TESTSCHRITT_ID=aktiv.TESTSCHRITT_ID (+)
Group by
testschrit.testfall_id,
testschrit.testschritt_id,
testschrit.TESTSCHRITT_NR,
CAST(TESTSCHRITT_BEZEICHNUNG AS varchar(600)),
CAST(TESTSCHRITT_BESCHREIBUNG AS varchar(600))
order by test_case_id,
testschrit.testschritt_nr
)
group by test_case_id;
CREATE TABLE Project.ITERATIONS
(
Issue_Id NUMBER(9,0),
iteration_id NUMBER(9,0),
content_of_iteration VARCHAR2(4000),
parent_id NUMBER(9,0),
Issue_type VARCHAR2(300),
Hierarchy1 VARCHAR2(300),
Hierarchy2 VARCHAR2(300),
summary_name VARCHAR2(300),
part_elements VARCHAR2(300),
status VARCHAR2(300),
issue_category VARCHAR2(300),
relevance VARCHAR2(300),
planned_duration FLOAT,
description VARCHAR2(4000),
precondition VARCHAR2(300),
priority NUMBER(3,0),
assignee VARCHAR2(300),
expected_result VARCHAR2(300),
editor VARCHAR2(300),
modification_date DATE,
dok_ref VARCHAR2(4000),
activity VARCHAR2(4000),
ITERATIONSPARAMETER_NR NUMBER(9,0)
);
INSERT INTO Project.ITERATIONS
select
NULL as Issue_Id,
iter.testfall_id as iteration_id,
iter.testfall_id || ' ' || iter.ITERATIONSPARAMETER || ' ' || iter.ITERATIONSPARAMETER_BESCHREIBU as content_of_iteration,
tfb.TESTFALL_ID as parent_id,
'Iteration' as Issue_type,
NULL as Hierarchy1,
NULL as Hierarchy2,
'Iteration' ||' '|| iter.ITERATIONSPARAMETER_NR || ' - ' || tfb.FALL_BEZEICHNUNG as summary_name,
NULL as part_elements,
NULL as status,
NULL as issue_category,
NULL as relevance,
/* CASE (iter.ITERATIONSPARAMETER_NR) WHEN 0 THEN iter.ITERATIONSPARAMETER
ELSE ''
END
as naglowek,*/
NULL as planned_duration,
' |' || Replace(iter.ITERATIONSPARAMETER,';','|') || ' | |' ||iter.ITERATIONSPARAMETER_BESCHREIBU || ' |' as description,
NULL as precondition,
NULL as priority,
NULL as assignee,
NULL as expected_result,
NULL as editor,
NULL as modification_date,
NULL as dok_ref,
/* NULL as TESTSCHRITT_BEZEICHNUNG*/
/*NULL as activity*/
NULL as activity,
iter.ITERATIONSPARAMETER_NR as ITERATIONSPARAMETER_NR
FROM Project.TESTFALLBESCHREIBUNG tfb, Project.ITERATIONSPARAMETER iter
where
iter.testfall_id =tfb.testfall_id (+)
order by
Issue_Id,
iteration_id,
iter.ITERATIONSPARAMETER_NR ;
SELECT
distinct tfb.TESTFALL_ID as Issue_Id,
NULL as iteration_id,
NULL as content_of_iteration,
NULL as parent_id,
'Test_case' as Issue_type,
REPLACE(globale.testbezeichnung, ' ','_') as Hierarchy1,
REPLACE(voraus.voraussetzungs_bezeichnung,' ' , '_') as Hierarchy2,
CAST(FALL_BEZEICHNUNG AS varchar(150)) as summary_name,
CAST(BETEILIGTE_ELEMENTE AS varchar(100)) as part_elements,
status.testfall_status_beschreibung as status,
(CASE FEHLERFREIHEIT || ' ' || WIDERSPRUCHSLOSIGKEIT || ' ' || VOLLSTÄNDIGKEIT WHEN '0 0 0' THEN ''
ELSE '' END) ||
(CASE FEHLERFREIHEIT || ' ' || WIDERSPRUCHSLOSIGKEIT || ' ' || VOLLSTÄNDIGKEIT WHEN '-1 0 0' THEN 'FEHLERFREIHEIT'
ELSE '' END) ||
(CASE FEHLERFREIHEIT || ' ' || WIDERSPRUCHSLOSIGKEIT || ' ' || VOLLSTÄNDIGKEIT WHEN '-1 -1 0' THEN 'FEHLERFREIHEIT WIDERSPRUCHSLOSIGKEIT'
ELSE '' END) ||
(CASE FEHLERFREIHEIT || ' ' || WIDERSPRUCHSLOSIGKEIT || ' ' || VOLLSTÄNDIGKEIT WHEN '-1 -1 -1' THEN 'FEHLERFREIHEIT WIDERSPRUCHSLOSIGKEIT VOLLSTÄNDIGKEIT'
ELSE '' END) ||
(CASE FEHLERFREIHEIT || ' ' || WIDERSPRUCHSLOSIGKEIT || ' ' || VOLLSTÄNDIGKEIT WHEN '0 -1 0' THEN 'WIDERSPRUCHSLOSIGKEIT'
ELSE '' END) ||
(CASE FEHLERFREIHEIT || ' ' || WIDERSPRUCHSLOSIGKEIT || ' ' || VOLLSTÄNDIGKEIT WHEN '0 -1 -1' THEN 'WIDERSPRUCHSLOSIGKEIT VOLLSTÄNDIGKEIT'
ELSE '' END)||
(CASE FEHLERFREIHEIT || ' ' || WIDERSPRUCHSLOSIGKEIT || ' ' || VOLLSTÄNDIGKEIT WHEN '-1 0 -1' THEN 'FEHLERFREIHEIT VOLLSTÄNDIGKEIT'
ELSE '' END) ||
(CASE FEHLERFREIHEIT || ' ' || WIDERSPRUCHSLOSIGKEIT || ' ' || VOLLSTÄNDIGKEIT WHEN '0 0 -1' THEN 'VOLLSTÄNDIGKEIT'
ELSE '' END) as issue_category,
(CASE ELEMENTTEST || ' ' || INTEGRATIONSTEST || ' ' || SYSTEMTEST WHEN '0 0 0' THEN ''
ELSE '' END) ||
(CASE ELEMENTTEST || ' ' || INTEGRATIONSTEST || ' ' || SYSTEMTEST WHEN '-1 0 0' THEN 'ELEMENTTEST'
ELSE '' END) ||
(CASE ELEMENTTEST || ' ' || INTEGRATIONSTEST || ' ' || SYSTEMTEST WHEN '-1 -1 0' THEN 'ELEMENTTEST INTEGRATIONSTEST'
ELSE '' END) ||
(CASE ELEMENTTEST || ' ' || INTEGRATIONSTEST || ' ' || SYSTEMTEST WHEN '-1 -1 -1' THEN 'ELEMENTTEST INTEGRATIONSTEST SYSTEMTEST'
ELSE '' END) ||
(CASE ELEMENTTEST || ' ' || INTEGRATIONSTEST || ' ' || SYSTEMTEST WHEN '0 -1 0' THEN 'INTEGRATIONSTEST'
ELSE '' END) ||
(CASE ELEMENTTEST || ' ' || INTEGRATIONSTEST || ' ' || SYSTEMTEST WHEN '0 -1 -1' THEN 'INTEGRATIONSTEST SYSTEMTEST'
ELSE '' END)||
(CASE ELEMENTTEST || ' ' || INTEGRATIONSTEST || ' ' || SYSTEMTEST WHEN '-1 0 -1' THEN 'ELEMENTTEST SYSTEMTEST'
ELSE '' END) ||
(CASE ELEMENTTEST || ' ' || INTEGRATIONSTEST || ' ' || SYSTEMTEST WHEN '0 0 -1' THEN 'SYSTEMTEST'
ELSE '' END) as relevance,
/* NULL as head, */
tfb.GEPLANTER_AUFWAND as planned_duration,
CAST(BESCHREIBUNG_TESTFALL AS varchar(4000)) as description,
CAST(AUSGANGSSITUATION AS varchar(200)) as precondition,
WICHTIGKEIT as priority,
BEARBEITER as assignee,
CAST(ERWARTETE_ERGEBNISSE AS varchar(200)) as expected_result,
LETZTER_BEARBEITER as editor,
DATUM_LETZTE_ÄNDERUNG as modification_date,
Replace(LISTAGG( dokref.dokumentenreferenz, chr(10)) within group (order by dokref.dokumentenreferenz),' ','_') as dok_ref,
steps.test_step as activity,
NULL as ITERATIONSPARAMETER_NR
FROM Project.TESTFALLBESCHREIBUNG tfb, Project.TEST_STEPS steps,Project.NM_TESTFALL_DOKUMENTENREFERENZ nmdokref,
Project.DOKUMENTENREFERENZ dokref, Project.TESTFALL_STATUS status, Project.VORAUSSETZUNGEN voraus, Project.GLOBALE_ANGABEN globale,
Project.NM_TESTFÄLLE_STICHWORTE stich, Project.STICHWORTE stichworte
WHERE tfb.testfall_id=steps.test_case_id (+)
AND tfb.testfall_id= nmdokref.testfall_id (+)
AND nmdokref.dokumentenreferenz_id= dokref.dokumentenreferenz_id(+)
AND tfb.testfall_status= status.testfall_status (+)
AND tfb.voraussetzung_id=voraus.voraussetzung_id (+)
AND voraus.tz_id= globale.tz_id (+)
AND tfb.testfall_id= stich.testfall_id (+)
AND stich.stichworte_id= stichworte.stichwort_id (+)
GROUP BY
tfb.TESTFALL_ID,
globale.testbezeichnung,
status.testfall_status_beschreibung,
voraus.voraussetzungs_bezeichnung,
CAST(FALL_BEZEICHNUNG AS varchar(200)) ,
CAST(BETEILIGTE_ELEMENTE AS varchar(200)),
FEHLERFREIHEIT,
WIDERSPRUCHSLOSIGKEIT,
VOLLSTÄNDIGKEIT,
ELEMENTTEST,
INTEGRATIONSTEST,
SYSTEMTEST,
tfb.GEPLANTER_AUFWAND,
CAST(BESCHREIBUNG_TESTFALL AS varchar(200)),
CAST(AUSGANGSSITUATION AS varchar(200)),
WICHTIGKEIT,
BEARBEITER,
CAST(ERWARTETE_ERGEBNISSE AS varchar(200)),
LETZTER_BEARBEITER,
DATUM_LETZTE_ÄNDERUNG,
status.testfall_status_beschreibung,
stichworte.stichwort,
steps.test_step
UNION ALL
select * from Project.ITERATIONS

DB2 - Ways to get multiple positions for character in a string

So I am having the pleasure of working with a very old database that apparently was setup before the invention of normalization. I have been asked to see if I can come up with a way to make it work right.
The first table actually has something like a real primary key.
example:
ID, Reason
--- ----------
1, Write off
2, Overage
3, OLH
The problem is the other table...
CustomerNum, JobNum, Reasons
------------ ------- ---------------------
42351, 46, X
32313, 456, X
85472, 13, X X
How are these tables joined in their system? Yup, the position of the X's in the line. So if the X is in the first position, it's the reason 1, second position, reason 2, and so on. It's essentially a flat array. And that wouldn't be to bad actually, if they limited it to 1 X per line... (LOCATE('X', REASONS) as XINDEX) but that's not the case. In theory there are 21 possible X's that could be checked on each line.
So I have to give them a recommendation on how to make it work.
One of my first recommendations will be to create a separate table and normalize the tables, however I don't know how well that will go over, or if they would be willing to change their system.
So, I would also like to suggest something like a stored procedure that would be able to go through each line and return the indexes as if they were in a separate table.
I don't know if this is possible, but I'm hopeful.
EDIT
So yeah, I'm really going to push the linking table.
here's the alternative that I've got working from the suggestions:
Select tblCustomers.*,
CASE WHEN SUBSTRING(Reasons,1,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 1)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,2,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 2)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,3,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 3)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,4,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 4)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,5,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 5)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,6,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 6)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,7,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 7)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,8,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 8)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,9,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 9)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,10,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 10)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,11,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 11)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,12,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 12)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,13,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 13)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,14,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 14)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,15,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 15)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,16,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 16)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,17,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 17)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,18,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 18)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,19,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 19)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,20,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 20)) || ', ' ELSE '' END
|| CASE WHEN SUBSTRING(Reasons,21,1) = 'X' THEN RTRIM((SELECT Reason FROM tblReasons WHERE ID = 21)) || ', ' ELSE '' END AS XPOS
From tblCustomers
I'm going to have to play with Marlin's suggestion a bit to see how much it streamlines it, but one thing I do like about this query is that it shows how ridiculous their current layout is, and why they should change it.
I'd really pitch the new linking table, but here is either the meat of the stored procedure, or the way to populate the linking table:
SELECT Customers.CustomerNum, Reasons.ID
FROM Customers, Reasons
WHERE SUBSTR(Customers.Reasons, Reasons.ID, 1) = 'X'
first thing I would do is to create a new column for each possible position of the X (so if there are 10 positions -> 10 new cols) and give those columns meaningful names. then you can write queries easier...

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]