Postgres statement pipes enclosing quoted colons - sql

What does it mean when a SQL statement in postgres is written like the following?
SELECT
name||' ::: '||id AS title
FROM
my_table;
It's almost impossible to search in Google! What do the pipes and enclosed quoted colons do?

From the fine manual:
Function: string || string
Return Type: text
Description: String concatenation
Example: 'Post' || 'greSQL'
Result: PostgreSQL
So a || b is string concatenation. This is standard SQL, some non-standard databases use concat(a, b) or a + b.
Single quotes are used in (standard) SQL for string literals so ' ::: ' is just a string.
That means that the whole thing:
name||' ::: '||id
is just the name and id pasted together with ' ::: ' between them. That SQL would probably be easier to read if the author added a little bit of whitespace:
name || ' ::: ' || id
BTW, you'll have better luck using SymbolHound to search for such things:
http://symbolhound.com/?q=postgresql+%7C%7C

This simply do a select statement for two fields of the table by concatenating them with a text ' ::: ' at the middle.

Related

SQL Using LIKE and ANY at the same time

I have a table with a column feature of type text and a text array (text[]) named args. I need to select from the table those rows in which the feature column contains at least one of the elements of the args array.
I've tried different options, including this:
SELECT * FROM myTable WHERE feature LIKE '%' + ANY (args) + '%';
But that does not work.
The simple solution is to use the regular expression match operator ~ instead, which works with strings in arg as is (without concatenating wildcards):
SELECT *
FROM tbl
WHERE feature ~ ANY(args);
string ~ 'pattern' is mostly equivalent to string LIKE '%pattern%', but not exactly, as LIKE uses different (and fewer) special characters than ~. See:
Escape function for regular expression or LIKE patterns
If that subtle difference is not acceptable, here is an exact implementation of what you are asking for:
SELECT *
FROM tbl t
WHERE t.feature LIKE ANY (SELECT '%' || a || '%' FROM unnest(t.args) a);
Unnest the array, pad each element with wildcards, and use LIKE ANY with the resulting set.
See:
IN vs ANY operator in PostgreSQL

SELECT if string contains column value

Manufacturer
==========================
id name
--------------------------
1 Company Inc.
2 Google Test.
3 3M (UNITY) USA. INC.
4 CE EE
Say, I have a string 'Google Test. 1257 SCS RANDOM 31233DD' and I want to find all rows in table manufacturer where ht name is part of the given string:
SELECT * FROM manufacturer
WHERE 'Google Test. 1257 SCS RANDOM 31233DD' ILIKE '%' || name || '%'
Correctly returns:
id name
--------------------------
2 Google Test.
But when I do:
SELECT * FROM manufacturer
WHERE '3dad QTICE EEN ' ILIKE '%' || name || '%'
it returns:
id name
--------------------------
4 CE EE
I don't want partial matches like this. The name shall not match in the middle of a word. I tried substring():
SELECT * from manufacturer
WHERE SUBSTRING('Google Test. 1257 SCS RANDOM 31233DD' from name) != '';
But I get:
ERROR: invalid regular expression: quantifier operand invalid
Unfortunately I don't have the exact spec to go off since I am querying this off external db. But from what I have seen, column is varchar(256). All values are upper cased and use plain spaces. All start with either character or number and end with either number, char, or special character. Ex: 'CLEVLAND DRILL (GREEN)'. There are special characters in the value, such as ,.()&/
I am not really looking for efficiency as long as it doesn't take over 50ms to do one query.
As of right now, there are about 10000+ entries but it could def grow over time.
One method with LIKE is to add spaces to the begining and end:
SELECT *
FROM db
WHERE ' ' || '3dad QTICE EEN ' || ' ' ILIKE '% ' || manufacturer || ' %'
If you need more sophisticated matching, then you might need to use regular expressions with word boundaries.
All the values start with either character or a number and end with either number, char, or special character. ... There are special characters in the value, such as ,.()&/.
I suggest the regular expression match operator ~. Carefully define boundaries and escape special characters in name:
Create once:
CREATE OR REPLACE FUNCTION f_regexp_escape(text)
RETURNS text AS
$func$
SELECT regexp_replace($1, '([!$()*+.:<=>?[\\\]^{|}-])', '\\\1', 'g')
$func$ LANGUAGE sql IMMUTABLE;
Then:
SELECT * FROM manufacturer
WHERE '3dad QTICE EEN ' ~ ('\m' || f_regexp_escape(name) || '( |$)')
How? Why?
\m .. beginning of a word. Works, since: values start with either character or number
( |$) .. a space or the end of the string. We need this since values: end with either number, char, or special character
The content of manufacturer.name is the core of the pattern. You want the literal meaning of all its characters, so strip any special meaning by escaping properly. This is true for LIKE (few special characters) as well as the regular expression match operator ~ (more special characters). Often overlooked and quite a pitfall. That got you (and the tricky definition of bounds). Read this!
Escape function for regular expression or LIKE patterns
And then use the function f_regexp_escape() as demonstrated. A name like:
3M (UNITY) USA. INC.
becomes:
3M \(UNITY\) USA\. INC\.
Might be convenient to store readily escaped patterns in table manufacturer, maybe as additional column. And maybe with added padding like this:
\m3M \(UNITY\) USA\. INC\.( |$)
Or generate the pattern on the fly like demonstrated.
This way name can be a single word or a whole phrase, and end with any characters. But start and end never match in the middle of a "word" on the other side.
There is an arsenal of other pattern matching tools in Postgres:
Pattern matching with LIKE, SIMILAR TO or regular expressions in PostgreSQL
If your table is big, consider the full text search infrastructure with optimized indexes and phrase search capability:
How to search hyphenated words in PostgreSQL full text search?
To solve this problem you really need to use regex, as adding a space either side of the string will not match at the beginning or end of the line. By using regex, we can check for that situation too. For example:
SELECT *
FROM manufacturer
WHERE 'Google Test. 1257 36700 SCS RANDOM WORD 31233DD' ~ ('(^| )' || name || '( |$)');
Output:
id name
2 Google Test.
Query:
SELECT *
FROM manufacturer
WHERE '3dad QTICE EEN ' ~ ('(^| )' || name || '( |$)');
Output:
There are no results to be displayed.
Query:
SELECT *
FROM manufacturer
WHERE 'CE EE ' ~ ('(^| )' || name || '( |$)');
Output:
id name
4 CE EE
Demo on dbfiddle
Update
Because the name values in the table can contain characters that have special meaning in a regex, they need to be escaped before the name is included into the regex. You can do this with REGEXP_REPLACE e.g.
REGEXP_REPLACE(name, '([\\.+*?[^\]$(){}=!<>|:\-#])', '\\\1', 'g')
So your query should be:
SELECT *
FROM manufacturer
WHERE 'Google Test. 1257 36700 SCS RANDOM WORD 31233DD' ~ ('(^| )' || REGEXP_REPLACE(name, '([\\.+*?[^\]$(){}=!<>|:\-#])', '\\\1', 'g') || '( |$)');
Updated demo

What is the line continuation character for HANA SQL?

What is the line-continuation character for HANA SQL? Considering I have a super long statement and want it to span across multiple lines instead of it being a super long one in a line.
Thanks.
For most SQL statements, you can implicitly continue on the next line. There is no "line-continuation character". Long strings can be continued on the next line by separating them in multiple strings concatenated with ||.
For example, this is perfectly valid HANA SQL:
SELECT
"RefID",
"FirstName",
"LastName"
FROM
"People"
WHERE
"FirstName" = 'Hubert Blaine'
AND
"LastName" = 'Wolfeschlegelsteinhausenbergerdorffvoralternwaren' ||
'gewissenhaftschaferswesenchafewarenwholgepflegeun' ||
'dsorgfaltigkeitbeschutzenvonangereifenduchihrraub' ||
'giriigfeindewelchevorralternzwolftausendjahresvor' ||
'andieerscheinenbanderersteerdeemmeshedrraumschiff' ||
'gebrauchlichtalsseinursprungvonkraftgestartseinla' ||
'ngefahrthinzwischensternartigraumaufdersuchenachd' ||
'iesternwelshegehabtbewohnbarplanetenkreisedrehens' ||
'ichundwohinderneurassevanverstandigmenshlichkeitt' ||
'konntevortpflanzenundsicherfreunanlebenslamdlichf' ||
'reudeundruhemitnichteinfurchtvorangreifenvonander' ||
'erintlligentgeschopfsvonhinzwischensternartigraum';
PS: That person actually exists. :)
You can hit the return key and have a statement split in multiple line for your convenience.
Like in the image below:
Even in dynamic SQL you can split the string (with the || operator) you're going to feed in the EXEC() command.

Oracle SQL - Is there a better way to concatenate multiple strings with a given delimiter?

First question, so apologies in advance if this is stupid or unoriginal, but I've searched for about 30 mins now without finding any mention anywhere of my exact question:
Is there a way to concatenate a series of strings, to be separated by a given delimiter, without manually putting the delimiter between each column being concatenated?
To give a concrete example, I currently have this:
SELECT member_no as Member#,
(member_gname
|| ' '
|| member_fname) as Name,
(member_street
|| ' '
|| member_city
|| ' '
|| member_state
|| ' '
|| member_postcode) AS Address,
member_phone AS Phone,
TO_CHAR(member_joindate, 'dd-Mon-yyyy') as Joined
FROM MEMBER;
It works fine, and produces exactly the output I wanted, but as this is for study I'm less concerned about the output and more concerned with the readability and 'best practise' factors of the .sql file itself. I understand that CONCAT() only takes two arguments, so that won't work without nesting them (which is even uglier and less readable). I'm coming in totally naively here, but I was hoping there'd be some kind of magical AWESOMECONCAT() type of function that would take all the columns i need, as well as allowing me to specify what character I want separating them (in this case, a space). Any ideas?
Also, this is a separate question not worthy of posting by itself, but is there any way to select a column 'AS' and give it a name including whitespace? E.g 'Member #' would look better imo, and 'Join Date' would be clearer, but I've tried both brackets and single quotes after the AS and neither seems to fly with SQL developer.
We can still write our own AWESOMECONCAT(). Unfortunately, Oracle has no in built function. As the concatenate operator does the basic thing.
Using double quotes in the alias, you can make the column references case sensitive and even accept blanks. But note that, any more references to that column/expression needs double quotes with same text.
SELECT member_no as "Member #",
(member_gname
|| ' '
|| member_fname) as Name,
(member_street
|| ' '
|| member_city
|| ' '
|| member_state
|| ' '
|| member_postcode) AS Address,
member_phone AS Phone,
TO_CHAR(member_joindate, 'dd-Mon-yyyy') as "Join Date"
FROM MEMBER;
Is there a way to concatenate a series of strings, to be separated by a given delimiter, without manually putting the delimiter between each column being concatenated?
The best way to do concatenation from 11g onwards is the new string literal technique q'[]'.
For example :
select q'[This is a string, 'this is also a string'.]' from dual

SQL substr query

I need to understand this query as best as possible, thanks
substr(b_Aplicacion,1,4)
|| '-'
|| substr(b_Aplicacion,5,2)
|| '-'
|| substr(b_Aplicacion,7,2)
I assume you're aware of how the substr() function works. (If not, here's an explanation.)
In PLSQL || is a string concatenation operator.
Example: 'left' || ' - ' || 'right' evaluates to 'left - right'
Your example looks like it's reformatting a string that probably is a date like 20120102 into 2012-01-02
This expression inserts dashes into the string after the 4-th and 6-th position, and throws away characters after the 8-th position. For example, abcdefghijkl becomes abcd-ef-gh.
Substr cuts out three parts from the string: abcd, ef, and gh in my example. || '-' || glues the parts back together, inserting dashes in between. || between two string expressions represent concatenation, i.e. it makes one string by gluing the part on its left to the part on its right.
substr( string, start_position, [ length ] ) is performed like this:
string is the source string.
start_position is the position for extraction. The first position in the string is always 1.
length is optional. It is the number of characters to extract. If this parameter is omitted, substr will return the entire string.
The || represents concatenation.
So that query is separating the placcing a '-' character after 4th and 6th positions.
For example, if you have 20121221 as b_Aplicacion that query will return 2011-12-21.