floating schema definition of table - how to in pl/sql - postgresql

I’m new to pl/SQL and would like to get some advice on whether this code snippet could be written in a more generic way.
What I mean by general is that I may get the new ‘source data’, in which the schema may vary. For example, what is currently available as:
name_1, name_2, lakename_1 in other ‘source data’ might be available under different names, and the number of the column might be also different.
Ideally would be to have one section of the code in which the names of columns could be defined. This is probably where pl/SQL come into the action.
Thank you in advance for assistance with it.
SELECT
nid,
name_1,
name_2,
lakename_1,
lakename_2,
rivname_1,
rivname_2,
concat_ws(',', "name_1", "name_2", "lakename_1", "lakename_2", "rivname_1", "rivname_2" ) concated_names,
---number of names
(
(CASE WHEN name_1 != '' THEN '1' ELSE '0' END)::integer +
(CASE WHEN name_2 != '' THEN '1' ELSE '0' END)::integer +
(CASE WHEN lakename_1 != '' THEN '1' ELSE '0' END)::integer +
(CASE WHEN lakename_2 != '' THEN '1' ELSE '0' END)::integer +
(CASE WHEN rivname_1 != '' THEN '1' ELSE '0' END)::integer +
(CASE WHEN rivname_2 != '' THEN '1' ELSE '0' END)::integer
) number_of_names,
---unique combinations of names occurence
(
(CASE WHEN name_1 != '' THEN 'name1' ELSE '' END) || ',' ||
(CASE WHEN name_2 != '' THEN 'name2' ELSE '' END) || ',' ||
(CASE WHEN lakename_1 != '' THEN 'lakename_1' ELSE '' END) || ',' ||
(CASE WHEN lakename_2 != '' THEN 'lakename_2' ELSE '' END) || ',' ||
(CASE WHEN rivname_1 != '' THEN 'rivname_1' ELSE '' END) || ',' ||
(CASE WHEN rivname_2 != '' THEN 'rivname_2' ELSE '' END)
) unique_names
,
geom
INTO canada_merged.number_of_names_per_features
FROM
canada_merged.waterbody_and_waterlines
where name_1 !=''
or name_2 !=''
or lakename_1 !=''
or lakename_2 !=''
or rivname_1 !=''
or rivname_2 !='';

Related

Postgres CASE expression then null

The below query is part of a select query which I have got in my application
where
case when o.tracking_id <> '0' then a.account_id is null
and
o.status = 'N'
else
(
o.tracking_id = '0'
and
o.status = 'N'
)
END
I am having hardtime to understand the below line
Can you please tell me what does this exactly mean ?
case when o.tracking_id <> '0' then a.account_id is null
I wouldn't use a CASE expression here but instead would use the following logic:
WHERE
(o.tracking_id <> '0' AND a.account_id IS NULL AND o.status = 'N')
OR
(o.tracking_id = '0' AND o.status = 'N')
The condition is written somewhat clumsily. It is equivalent to this more readable expression:
where (o.tracking_id = '0' or a.account is null)
and o.status = 'N';

Case when exists - column (SQL)

I'm trying to populate the field of an XML file with either '0', if a specific column (pv_an4) does not exist, OR with the value of the column, if it exists.
This is my code so far:
XMLELEMENT( Name "Telephone",
case
when not exists (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'phonebook' AND COLUMN_NAME = 'pv_an4') then ''
when exists (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'phonebook' AND COLUMN_NAME = 'pv_an4') then pv_an4
end ),
When I execute this I get this error:
FEHLER: Column »pv_an4« does not exist ZEILE 25: ...E_NAME =
'phonebook' AND COLUMN_NAME = 'pv_an4') then pv_an4
But this does make no sense to me, because for example with this code it would work:
....
when exists (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'phonebook' AND COLUMN_NAME = 'pv_an4') then 'pv_an4 exists'
end ),
....
I've spent the whole day trying to solve this problem, could someone hint me in the right direction, please?
/edit: Full query right below:
SELECT
XMLFOREST( xmlpb.entry as "DivinusIPPhoneDirectory" )
FROM (
SELECT
XMLCONCAT (
XMLELEMENT ( NAME "Title", 'Phonelist' ),
XMLELEMENT ( NAME "Prompt", 'Prompt' ),
XMLAGG (
XMLELEMENT (
NAME "DirectoryEntry",
XMLELEMENT( Name "Name",
case
when (pb.company = '') IS FALSE AND pb.lastname != '' and pb.firstname != '' then pb.company || ' - ' || pb.lastname || ', ' || pb.firstname
when (pb.company = '') IS FALSE AND pb.lastname != '' and pb.firstname = '' then pb.company || ' - ' || pb.lastname
when (pb.company = '') IS FALSE AND pb.lastname = '' and pb.firstname = '' then pb.company
when (pb.company = '') IS FALSE AND pb.lastname = '' and pb.firstname != '' then pb.company || ' - ' || pb.firstname
when (pb.company = '') IS NOT FALSE AND pb.lastname != '' and pb.firstname != '' then pb.lastname || ', ' || pb.firstname
when (pb.company = '') IS NOT FALSE AND pb.lastname != '' and pb.firstname = '' then pb.lastname
end ),
XMLELEMENT( Name "Telephone", pb.pv_an3 ),
XMLELEMENT( Name "Telephone",
case
when not exists (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'phonebook' AND COLUMN_NAME = 'pv_an4') then ''
else pb.pv_an4
end ),
XMLELEMENT( Name "Telephone", pb.phonenumber ),
XMLELEMENT( Name "Telephone", pb.pv_an1 ),
XMLELEMENT( Name "Telephone", pb.pv_an2 )
)
)
) as entry
FROM
phonebook pb
WHERE fkidtenant = 1
The whole sql statement is parsed and compiled before it is run, therefore postgresql will complain of the missing field. There is no shortcut.
You need to use dynamically generated sql if you want to handle such scenarios (check whether the column exists and create the appropriate sql statement). Although I cannot really imagine why you should not know if a certain column exists in a table or not.
Try:
XMLELEMENT( Name "Telephone",
case
when not exists (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'phonebook' AND COLUMN_NAME = 'pv_an4') then ''
when exists (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'phonebook' AND COLUMN_NAME = 'pv_an4') then 'pv_an4'
end ),
In line 4, you're using pv_an4 as a column in your first query, but as a column value in your second query.

Parse Prefix First Middle Last Suffix from full name

I need to parse a full name in the format, prefix first middle last suffix, but not all parts may be included. I have the prefix first middle and last working, but Jr gets stuffed in with the last name. How do I get the suffix to come out in a suffix column? Example includes data.
SELECT
FIRST_NAME.INPUT_DATA
,FIRST_NAME.PREFIX
,FIRST_NAME.FIRST_NAME
,CASE WHEN 0 = CHARINDEX(' ',FIRST_NAME.REMAINING)
THEN NULL --no more spaces found, consider remaining to be last name
ELSE SUBSTRING(
FIRST_NAME.REMAINING
,1
,CHARINDEX(' ',FIRST_NAME.REMAINING)-1
)
END AS MIDDLE_NAME
,SUBSTRING(
FIRST_NAME.REMAINING
,1 + CHARINDEX(' ',FIRST_NAME.REMAINING)
,LEN(FIRST_NAME.REMAINING)
) AS LAST_NAME
FROM
(
SELECT
PREFIX.PREFIX
,CASE WHEN 0 = CHARINDEX(' ',PREFIX.REMAINING)
THEN PREFIX.REMAINING --no space found, return the entire string
ELSE SUBSTRING(
PREFIX.REMAINING
,1
,CHARINDEX(' ',PREFIX.REMAINING)-1
)
END AS FIRST_NAME
,CASE WHEN 0 = CHARINDEX(' ',PREFIX.REMAINING)
THEN NULL --no spaces found, consider to be first name
ELSE SUBSTRING(
PREFIX.REMAINING
,CHARINDEX(' ',PREFIX.REMAINING)+1
,LEN(PREFIX.REMAINING)
)
END AS REMAINING
,PREFIX.INPUT_DATA
FROM
(
SELECT --CLEAN_DATA
--if first three characters match list,
--parse as a "PREFIX". else return NULL for PREFIX.
CASE WHEN SUBSTRING(CLEAN_DATA.FULL_NAME,1,3) IN ('MR ','MS ','DR ','MRS')
THEN LTRIM(RTRIM(SUBSTRING(CLEAN_DATA.FULL_NAME,1,3)))
ELSE NULL
END AS PREFIX
,CASE WHEN SUBSTRING(CLEAN_DATA.FULL_NAME,1,3) IN ('MR ','MS ','DR ','MRS')
THEN LTRIM(RTRIM(SUBSTRING(CLEAN_DATA.FULL_NAME,4,LEN(CLEAN_DATA.FULL_NAME))))
ELSE LTRIM(RTRIM(CLEAN_DATA.FULL_NAME))
END AS REMAINING
,CLEAN_DATA.INPUT_DATA
FROM
(
SELECT
--trim leading & trailing spaces to prepare for processing
--replace extra spaces in name
REPLACE(REPLACE(LTRIM(RTRIM(FULL_NAME)),' ',' '),' ',' ') AS FULL_NAME
,FULL_NAME AS INPUT_DATA
FROM
(
--test with test data, or table
--table
--SELECT CONTACT AS FULL_NAME
--FROM CONTACT
--test data
--/*
SELECT 'Andy D Where' AS FULL_NAME
UNION SELECT 'Cathy T Landers' AS FULL_NAME
UNION SELECT 'Ms Annie Wint There' AS FULL_NAME
UNION SELECT 'Frank Fields' AS FULL_NAME
UNION SELECT 'Howdy U Pokes Jr.' AS FULL_NAME
--*/
) SOURCE_DATA
) CLEAN_DATA
) PREFIX
) FIRST_NAME
--credits to JStyons of course
Hope this helps. I have only added Generational SUFFIX titles(Sr, Jr), If more are needed you could add to the Case statement as needed. I am also assuming that your Db is case insensitive.
Assumption (Business Rules):
First Name has no spaces
Middle Name has no spaces
Last name has no spaces
Prefix's are only of the form 'MR ','MS ','DR ','MRS' with no period "."
Suffix's are only of the form 'Sr', 'Jr', 'Sr.', 'Jr.'
The Database is case insensitive
IF OBJECT_ID('tempdb..#cte_SpaceFix') IS NOT NULL
DROP TABLE #cte_SpaceFix
;WITH cte_OriginalData (FullName)
AS (
SELECT 'Andy D Where'
UNION
SELECT 'Cathy T Landers'
UNION
SELECT 'Ms Annie Wint There'
UNION
SELECT 'Ms Annie Wint There Jr'
UNION
SELECT 'Mrs Annie There Jr'
UNION
SELECT 'Frank Fields'
UNION
SELECT 'Howdy U Pokes Jr.'
UNION
SELECT 'Howdy U Pokes Sr.'
UNION
SELECT 'Cathy T Landers Jr'
UNION
SELECT 'Landers Jr'
)
,cte_FullNameRemoveTail AS
(
SELECT LTRIM(RTRIM(FullName)) AS FullName
FROM cte_OriginalData
)
,cte_Parse_Prefix(Prefix,FullFirst_Prefix,FullName) AS
(
SELECT CASE
WHEN SUBSTRING(FullName, 1, 3) IN ('MR ','MS ','DR ','MRS')
THEN LTRIM(RTRIM(SUBSTRING(FullName, 1, 3)))
ELSE NULL
END AS Prefix,
CASE
WHEN SUBSTRING(FullName, 1, 3) IN ('MR ','MS ','DR ','MRS')
THEN LTRIM(RTRIM(SUBSTRING(FullName, 4, 8000)))
ELSE LTRIM(RTRIM(FullName))
END AS FullFirst_Prefix,
FullName
FROM cte_FullNameRemoveTail
)
,cte_Parse_Suffix(Prefix,FullFirst_Prefix_Suffix,Suffix,FullName) AS
(
SELECT Prefix,
CASE
WHEN RIGHT(FullFirst_Prefix,3) = ' JR' THEN LTRIM(RTRIM(SUBSTRING(FullFirst_Prefix,1,LEN(FullFirst_Prefix)-3)))
WHEN RIGHT(FullFirst_Prefix,4) = ' JR.' THEN LTRIM(RTRIM(SUBSTRING(FullFirst_Prefix,1,LEN(FullFirst_Prefix)-4)))
WHEN RIGHT(FullFirst_Prefix,3) = ' SR' THEN LTRIM(RTRIM(SUBSTRING(FullFirst_Prefix,1,LEN(FullFirst_Prefix)-3)))
WHEN RIGHT(FullFirst_Prefix,4) = ' SR.' THEN LTRIM(RTRIM(SUBSTRING(FullFirst_Prefix,1,LEN(FullFirst_Prefix)-4)))
ELSE LTRIM(RTRIM(FullFirst_Prefix))
END AS FullFirst_Prefix_Suffix,
CASE
WHEN RIGHT(FullFirst_Prefix,3) = ' JR'
OR RIGHT(FullFirst_Prefix,4) = ' JR.'
THEN 'Jr'
WHEN RIGHT(FullFirst_Prefix,3) = ' SR'
OR RIGHT(FullFirst_Prefix,4) = ' SR.'
THEN 'Sr'
ELSE NULL
END AS Suffix,
FullName
FROM cte_Parse_Prefix
)
,cte_SpaceFix(Prefix, FullFirst_Prefix_Suffix, Suffix, FullName) AS
(
SELECT Prefix,
CASE
WHEN LEN(FullFirst_Prefix_Suffix) - LEN(REPLACE(FullFirst_Prefix_Suffix, ' ', '')) > 2 THEN REPLACE(REPLACE(REPLACE(REPLACE(FullFirst_Prefix_Suffix,SPACE(5), SPACE(1)),SPACE(4), SPACE(1)),SPACE(3), SPACE(1)),SPACE(2), SPACE(1))
ELSE FullFirst_Prefix_Suffix
END AS FullFirst_Prefix_Suffix,
Suffix,
FullName
FROM cte_Parse_Suffix
)
SELECT * INTO #cte_SpaceFix
FROM cte_SpaceFix
;WITH cte_Parse_FirstName(Prefix, FirstName, Suffix, FullFirst_Prefix_Suffix_FirstName, FullName) AS
(
SELECT Prefix,
CASE
WHEN FullFirst_Prefix_Suffix IS NULL THEN NULL
WHEN LEN(FullFirst_Prefix_Suffix) - LEN(REPLACE(FullFirst_Prefix_Suffix, ' ', '')) >= 1 THEN LEFT(FullFirst_Prefix_Suffix,CHARINDEX(' ',FullFirst_Prefix_Suffix))
WHEN LEN(FullFirst_Prefix_Suffix) - LEN(REPLACE(FullFirst_Prefix_Suffix, ' ', '')) = 0 THEN FullFirst_Prefix_Suffix
ELSE NULL
END AS FirstName,
Suffix,
CASE
WHEN FullFirst_Prefix_Suffix IS NULL THEN NULL
WHEN LEN(FullFirst_Prefix_Suffix) - LEN(REPLACE(FullFirst_Prefix_Suffix, ' ', '')) >= 1 THEN LTRIM(RTRIM(REPLACE(FullFirst_Prefix_Suffix,LEFT(FullFirst_Prefix_Suffix,CHARINDEX(' ',FullFirst_Prefix_Suffix)),'')))
WHEN LEN(FullFirst_Prefix_Suffix) - LEN(REPLACE(FullFirst_Prefix_Suffix, ' ', '')) = 0 THEN NULL
ELSE NULL
END AS FullFirst_Prefix_Suffix_FirstName,
FullName
FROM #cte_SpaceFix
)
,cte_Parse_LastName(Prefix, FirstName, LastName, Suffix, MiddleName, FullName) AS
(
SELECT Prefix,
FirstName,
CASE
WHEN FullFirst_Prefix_Suffix_FirstName IS NULL THEN NULL
WHEN LEN(FullFirst_Prefix_Suffix_FirstName) - LEN(REPLACE(FullFirst_Prefix_Suffix_FirstName, ' ', '')) >= 1 THEN SUBSTRING(FullFirst_Prefix_Suffix_FirstName,CHARINDEX(' ',FullFirst_Prefix_Suffix_FirstName)+1,8000)
WHEN LEN(FullFirst_Prefix_Suffix_FirstName) - LEN(REPLACE(FullFirst_Prefix_Suffix_FirstName, ' ', '')) = 0 THEN FullFirst_Prefix_Suffix_FirstName
ELSE NULL
END AS LastName,
Suffix,
CASE
WHEN FullFirst_Prefix_Suffix_FirstName IS NULL THEN NULL
WHEN LEN(FullFirst_Prefix_Suffix_FirstName) - LEN(REPLACE(FullFirst_Prefix_Suffix_FirstName, ' ', '')) >= 1 THEN LEFT(FullFirst_Prefix_Suffix_FirstName,CHARINDEX(' ',FullFirst_Prefix_Suffix_FirstName))
ELSE NULL
END AS MiddleName,
FullName
FROM cte_Parse_FirstName
)
SELECT Prefix, FirstName, MiddleName, LastName, Suffix--, FullName
FROM cte_Parse_LastName
IF OBJECT_ID('tempdb..#cte_SpaceFix') IS NOT NULL
DROP TABLE #cte_SpaceFix

Why do two seemingly identical where clauses involving nulls produce different results

I'm trying to select all records that don't have a null in a particular column and it's value isn't in another table.
So this particular situation I want to get all 'Instructors' from an import table that aren't already in the Individuals table. Obviously I don't want any blank instructors. My first attempt I tried using in the where clause:
(Instructor IS NOT NULL OR Instructor <> '')
However the results still included all blank records. When I tried using
ISNULL(Instructor, '') <> ''
I got the desired result. I can't see how these two where clauses could possibly produce different results. To me it seems like ISNULL converting the value to empty string for comparison should have exactly the same outcome as comparing the column to null then to empty string. What am I missing here? I'm guessing it's to do with the oddness of null values.
Below are the full queries
SELECT * FROM [tempimporttblTrainingLog]
LEFT JOIN tblIndividual I ON [Instructor] = I.FirstName + ' ' + I.Surname
WHERE (I.FirstName + ' ' + I.Surname IS NULL) AND (Instructor IS NOT NULL OR Instructor <> '')
SELECT * FROM [tempimporttblTrainingLog]
LEFT JOIN tblIndividual I ON [Instructor] = I.FirstName + ' ' + I.Surname
WHERE (I.FirstName + ' ' + I.Surname IS NULL) AND (ISNULL(Instructor, '') <> '')
ISNULL(Instructor, '') <> '' (1)
is equivalent to
(Instructor IS NOT NULL AND Instructor <> '') (2)
not
(Instructor IS NOT NULL OR Instructor <> '') (3)
If Instructor IS NULL, (1) and (2) will return FALSE, when (3) returns TRUE.
Same for when Instructor = ''.
ISNULL(Instructor, '') <> ''
won't return blank records, and you have an OR in the
(Instructor IS NOT NULL OR Instructor <> '')
line, meaning it will return anything which isn't null as well as non blanks, did you mean to put an AND instead?

SQL Statement with IN CASE

SELECT user
FROM userlist zH with(nolock)
where zH.user in (case when zh.trait='1' then ('B', 'HO', 'KO', 'PL','APP','2A','2B') else ('O') end)
can this statement with the where-in-case work? i hope you get what i meant. thanks.
You can use nested case statement, like
SELECT user
FROM userlist zH with(nolock)
where 'true' =
(case when zh.trait = '1'
then
case when zH.user in ('B', 'HO', 'KO', 'PL','APP','2A','2B')
then 'true'
else 'false'
end
else
case when zH.user = 'O'
then 'true'
else 'false'
end
end)
SELECT [user]
FROM userlist zH WITH ( NOLOCK )
WHERE ( zh.trait = '1'
AND zH.[user] IN ( 'B', 'HO', 'KO', 'PL', 'APP', '2A', '2B' )
)
OR ( zh.trait <> '1'
AND zH.[user] IN ( 'O' )
)