What's wrong with this query? Doubling quotes error - sql

ERROR: Syntax error at or near "''"
I searched about putting single quotes and this way seemed to be correct, doubling quotes, but it's not working
SELECT
cod_rede_credenciada_produto,
rep.des_cnpj_loja,
emf.des_header_estabelecimento,
TRIM(COALESCE (cep.uf_logradouro, '''')),
TRIM(COALESCE(cep.cidade_logradouro, '''')),
TRIM(COALESCE (cep.bairro_ini_logradouro, emf.complresidencia)),
TRIM(COALESCE (cep.desc_tipo_logradouro, '''') || '' '' || COALESCE (cep.titulo_logradouro, '''') || '' '' || COALESCE (cep.nome_logradouro, emf.ruaresidencia) || '', '' || COALESCE (emf.numresidencia, '''')),
pro.des_produto,
des_cnpj_loja
FROM
solucoes.slereprede_credenciada_produto rep
INNER JOIN
solucoes.sleproproduto pro ON rep.cod_produto = pro.cod_produto
LEFT JOIN
empresafilha emf ON emf.cgc = rep.des_cnpj_loja
LEFT JOIN
caecep_cep cep ON cep.cep_logradouro = emf.cepresidencia

This is one problem:
|| '' '' ||
If you want a space:
|| ' ' ||
If you want single quotes with a space between them:
|| ''' ''' ||

Related

How to concatenate cols under special rules?

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

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;

Sanitize user input with the USING keyword in PL/pgSQL

This is how I create my search_term:
IF char_length(search_term) > 0 THEN
order_by := 'ts_rank_cd(textsearchable_index_col, to_tsquery(''' || search_term || ':*''))+GREATEST(0,(-1*EXTRACT(epoch FROM age(last_edited)/86400))+60)/60 DESC';
search_term := 'to_tsquery(''' || search_term || ':*'') ## textsearchable_index_col';
ELSE
search_term := 'true';
END IF;
I am having some trouble with a PLPGSQL function:
RETURN QUERY EXECUTE '
SELECT
*
FROM
articles
WHERE
$1 AND
' || publication_date_query || ' AND
primary_category LIKE ''' || category_filter || ''' AND
' || tags_query || ' AND
' || districts_query || ' AND
' || capability_query || ' AND
' || push_notification_query || ' AND
' || distance_query || ' AND
' || revision_by || ' AND
' || publication_priority_query || ' AND
' || status_query || ' AND
is_template = ' || only_templates || ' AND
status <> ''DELETED''
ORDER BY ' || order_by || ' LIMIT 500'
USING search_term;
END; $$;
returns ERROR:
argument of AND must be type boolean, not type text at character 64
As opposed to:
RETURN QUERY EXECUTE '
SELECT
*
FROM
articles
WHERE
' || search_term || ' AND
' || publication_date_query || ' AND
primary_category LIKE ''' || category_filter || ''' AND
' || tags_query || ' AND
' || districts_query || ' AND
' || capability_query || ' AND
' || push_notification_query || ' AND
' || distance_query || ' AND
' || revision_by || ' AND
' || publication_priority_query || ' AND
' || status_query || ' AND
is_template = ' || only_templates || ' AND
status <> ''DELETED''
ORDER BY ' || order_by || ' LIMIT 500';
END; $$;
... which works. Am I missing something?
My goal is to sanitize my user input.
If some of your input parameters can be NULL or empty and should be ignored in this case, you best build your whole statement dynamically depending on user input - and omit respective WHERE / ORDER BY clauses completely.
The key is to handle NULL and empty string correctly, safely (and elegantly) in the process. For starters, search_term <> '' is a smarter test than char_length(search_term) > 0. See:
Best way to check for "empty or null value"
And you need a firm understanding of PL/pgSQL, or you may be in over your head. Example code for your case:
CREATE OR REPLACE FUNCTION my_func(
_search_term text = NULL -- default value NULL to allow short call
, _publication_date_query date = NULL
-- , more parameters
)
RETURNS SETOF articles AS
$func$
DECLARE
sql text;
sql_order text; -- defaults to NULL
BEGIN
sql := concat_ws(' AND '
,'SELECT * FROM articles WHERE status <> ''DELETED''' -- first WHERE clause is immutable
, CASE WHEN _search_term <> '' THEN '$1 ## textsearchable_index_col' END -- ELSE NULL is implicit
, CASE WHEN _publication_date_query <> '' THEN 'publication_date > $2' END -- or similar ...
-- , more more parameters
);
IF search_term <> '' THEN -- note use of $1!
sql_order := 'ORDER BY ts_rank_cd(textsearchable_index_col, $1) + GREATEST(0,(-1*EXTRACT(epoch FROM age(last_edited)/86400))+60)/60 DESC';
END IF;
RETURN QUERY EXECUTE concat_ws(' ', sql, sql_order, 'LIMIT 500')
USING to_tsquery(_search_term || ':*') -- $1 -- prepare ts_query once here!
, _publication_date_query -- $2 -- order of params must match!
-- , more parameters
;
END
$func$ LANGUAGE plpgsql;
I added default values for function parameters, so you can omit params that don't apply in the call. Like:
SELECT * FROM my_func(_publication_date_query => '2016-01-01');
More:
Functions with variable number of input parameters
The forgotten assignment operator "=" and the commonplace ":="
Note the strategic use of concat_ws(). See:
How to concatenate columns in a Postgres SELECT?
Here is a related answer with lots of explanation:
Test for null in function with varying parameters

Select statement inside Concatenate (Oracle)

I have complex Select statement in Oracle, with Case When conditions and they select all Concatenate values.
So something similar to this:
END
END
FROM something
...
What I need is to put Other value from other table instead of My Value in concatenate.
So Instead of (My Value) I would have:
(Select textValue from textView A where A.textID = '395')
If I run this statement alone, it will take out one exact value I want. However if I put it instead of (My Value) into concatenate it gives me error: ora-00936 missing expression
(Yes '395' is string in that other table)
Any Ideas please?
You can use inline views inside the case clause in Oracle. Isn't that what you are trying to do? "Missing expression" error is probably a missing bracket or some similar code error.
select case object_type
when 'TABLE' then
'select * from ' || object_name
when 'SYNONYM' then
'describe ' || object_name
when 'PACKAGE' then
(select to_char (count (*))
from user_source s
where s.type = o.object_type and s.name = o.object_name)
else
(select object_type from dual)
end
as objects
from user_objects o
Or simply create a function that returns that does this for you and call it.
create function gettextval (p_textid in varchar2)
return varchar2 is
l_returnval varchar2 (32767);
begin
select text_val
into l_returnval
from v_texts s
where s.text_id = p_textid;
return l_returnval;
exception
when no_data_found then
return p_textid;
end;
In this example I make it return the input string of nothing is found.
Then you can reference the function in your previous select.
' || gettextval('395') || '
can you post you query with the "select text" bit inside?
When use case->when i do like that:
SELECT
CASE A.LIST_TYPE_CD
WHEN '1' THEN '<A HREF="censured?thresholdId=censured' || GET_SITE_SUFFIX() || chr(38) || 'task=runSQL' || chr(38) || 'parseParams=true' || chr(38) || 'list_id=' || A.LIST_ID || chr(38) || 'list_name=' || A.LIST_NAME ||
'">' || (Select textValue from textView A where A.textID = '395') || '</A>'
WHEN '3' THEN '<A HREF=censured' || GET_SITE_SUFFIX() || chr(38) || 'task=runSQL' || chr(38) || 'parseParams=true' || chr(38) || 'list_id=' || A.LIST_ID ||
'">' || (Select textValue from textView B where B.textID = '395') || '</A>'
END
FROM something A