PSQL: Concatenate a value with LIKE in stored procedure - sql

I am trying to concatenate a variable using the LIKE statement and for some reason it only finds values where the word to search is at the end of the text variable.
I am using PostgreSQL 8.4 and this is stored in a function (stored procedure)
considering in this example:
a.key1 is "HELLO"
a_text is "I SAY HELLO TO THE WORLD"
Code:
SELECT count(1), a.key1, a.active, a.campkeydbid
FROM campkeydb a
WHERE a_text LIKE '%'|| a.key1 ||'%'
GROUP BY a.key1, a.active, a.campkeydbid
INTO a_count, a_campaignkey, a_active, a_campkeydbid;
In this stored procedure it will NOT return the values; it will not find the word "HELLO"?
It will ONLY return the values if a_text contains "I SAY HELLO"
Does anyone knows what I am doing wrong? It seems that it is correct as I am concatenating a % on both sides of the variable a.key1.

You can use the position string function instead of like. Here is a sample query using a table of the regions and departments of France. I'll try and find all the departments that have a name that includes the region name.
select r.name as region, d.name as deprtment, position( r.name in d.name) as pos
from regions r
join departments d on d.region = r.code
where position( r.name in d.name) != 0
and r.name != d.name;
The results are
region department pos
"Corse" "Corse-du-Sud" 1
"Corse" "Haute-Corse" 7
I added the pos column to show that strings are indexed from 1, not 0. I tried the same thing with 'like' (both queries have the same query plan and should give the same performance):
select r.name as region, d.name as deprtment, position( r.name in d.name) as pos
from regions r
join departments d on d.region = r.code
where d.name like '%' || r.name || '%'
and r.name != d.name;
I like the appearance of the first query, but they both do the same thing. So your logic seems correct, so this seems like a typo in a string.

Related

In SELECT, correlated subquery in select to transform rowID into rowname

How to combine these 2 sets of code?
Tables: geregistreerd g, instrument i and indeling id.
I want to display g.voornaammuzikant, g.achternaammuzikant, i.naaminstrument, id.familie.
Table g is linked with table i with instrumentid
Table i is linked with table id with indelingid
--oefening 1:
SELECT TRIM(' ' FROM g.voornaammuzikant), TRIM(' ' FROM g.achternaammuzikant),
(SELECT i.naaminstrument
from instrument i
where i.instrumentid = g.instrumentid) as "naam instrument"
from geregistreerd g
order by g.voornaammuzikant;
--oefening 2:
SELECT i.naaminstrument,
(SELECT id.familie
from indeling id
where i.indelingid = id.indelingid) as "familie",
(SELECT id.onderfamilie
from indeling id
where i.indelingid = id.indelingid) as "onderfamilie"
from instrument i
order by i.naaminstrument;
COMBINED
SELECT TRIM(' ' FROM g.voornaammuzikant),
TRIM(' ' FROM g.achternaammuzikant),
(SELECT i.naaminstrument
(SELECT id.familie
from indeling id
where i.indelingid = id.indelingid) as "familie"
from instrument i
where i.instrumentid = g.instrumentid) as "naam instrument"
from geregistreerd g
order by g.voornaammuzikant;
Why would you want to do things in a complicated way, if they can be simplified? What's wrong with a simple join? Something like this:
select g.voornaammuzikant,
g.achternaammuzikant,
i.naaminstrument,
id.familie
from geregistreerd g join instrument i on i.instrumentid = g.instrumentid
join indeling id on id.indelingid = i.indelingid
order by g.voornaammuzikant;
By the way, those TRIMs you posted don't look good. SELECT TRIM(' ' FROM g.voornaammuzikant) is certainly wrong; I don't know what you meant to say with that. Perhaps removing superfluous spaces from those values? If they exist, is - by any chance - that column's datatype CHAR? If so, consider switching to VARCHAR2 because the former pads values with spaces up to the whole length of that column.

SQL query to find matches

I have written a query to provide matches with the same DB and it's giving me expected results except that I don't get few part of it. Below is the query :
select f.name, f.id, f.industry, d.name, d.id, d.industry
from product_table f, product_table d
where (f.name like '%' || d.name || '%') and
(f.industrylike '%' || d.industry|| '%') and
I know by providing this it's actually looking for matches between the 2 columns :
(..... like '%' || ..... || '%')
But what does each part of it do exactly and what does it mean?
This query is executing a self-join (here, a cross self-join) in which we query two instances of the same table for some purpose. In this case it looks like some form of data quality exercise, where we suspect we might have almost duplicate records. That is, we think we have records for the same combination of (product name and industry). The use of wild cards will identify records where the value of one column is wholly embedded in another column: for instance '%STACK%' matches 'META STACKOVERFLOW'.
The posted version has a potential flaw, in that if there are two records with an exact match you will get two hits (one for F:D, one for D:F). You can finagle that by adding a filter on id
select f.name, f.id, f.industry,
d.name, d.id, d.industry
from product_table f, product_table d
where (f.name like '%' || d.name || '%')
and (f.industrylike '%' || d.industry|| '%')
and ( ( f.name = d.name
and f.industry = d.industry
and f.id < d.id )
or f.name != d.name
or f.industry != d.industry
)
The double vertical bar (more commonly known as a pipe) is the concatenation operator. It is used for joining strings together. (Many programming languages use + but Oracle reserves that strictly for arithmetic on numbers.)
not so much clear on why we put it before and after only the second column : f.name like '%' || d.name || '%'
In this case, the query is concatenating a wild card. Given this value for f.name = 'XYZ' , we would get matches for '%' || d.name || '%' on:
'1XYZ1'
'11XYZ11'
'11XYZ'
'XYZ1'
'XYZ' <---- matching same record
We don't need to wrap f.name in wildcard operators because the query is a self-join so all the values of name will appear on the left hand side of the filter. When f.name = '1XYZ1' it match for '%' || d.name || '%' on:
'1XYZ1' <---- matching same record
'XYZ1'
'XYZ'
So you're going to get multiple hits already. Embedding both sides of the filter in wildcards will only generate more noisy duplicates.

PostgreSQL - join tables using pattern matching

I have two tables and need to join them using two columns that are similar.
The first table is called articles has a column called 'slug' with slug lines for articles, ex: 'trump-fails-yet-again.'
The second table is called log and has a column called path with the url path for the articles, ex: '/articles/trump-fails-yet-again/'
Here is my search query:
"SELECT articles.title, count(*) as num FROM articles, log WHERE articles.slug LIKE CONCAT('%',log.path) GROUP BY articles.title;"
This returns nothing but brackets, []
I have also tried:
"SELECT articles.title, count(*) as num FROM articles JOIN log ON articles.slug SIMILAR TO CONCAT('%',log.path) GROUP BY articles.title;"
That returns a DataError: invalid regular expression: quantifier operand invalid
Any help is greatly appreciated!
try this:
` select articles.title, count(*) as views from articles
join log on articles.slug ~~ ('%' || articles.slug || '%')
group by articles.title;`
You have a slash at the end of the path. How about this?
SELECT a.title, count(*) as num
FROM articles a JOIN
log l
ON a.path LIKE '%' || l.slug || '%'
GROUP BY a.title;
You should also learn to use proper, explicit JOIN syntax. Never use commas in the FROM clause.
Because there is a 1:1 function with this you can do this
SELECT articles.title, count(*) as num
FROM articles
JOIN log ON articles.slug = '/articles/' || articles.slug || '/'
GROUP BY articles.title;
Or even better
CREATE FUNCTION slug_to_article_path( slug text )
RETURNS text AS
$$
SELECT '/articles/' || slug || '/';
$$ LANGUAGE sql
IMMUTABLE;
SELECT articles.title, count(*) as num
FROM articles
JOIN log ON articles.slug = slug_to_article_path(articles.slug)
GROUP BY articles.title;

Search string in SQL with action on table

I found on internet some stored procedure to search string in database, regularly it's used by table name.
My procedure contains a SELECT statement like this:
select distinct s.name
from sysobjects s
inner join syscomments c on c.id = s.id
and charindex(#keyword,c.text) > 0
where s.type IN ('V', 'P')
order by 1
My action want more than this, I want to search table name with action on that like insert, update or select. It means only find table name(keyword) has action insert or update or select and show me where it's used (procedure name, view...)
Is it possible to do?
First, dont use sysobjects and syscomments as they have been deprecated for quite some time now.
If you just care that the word appears in the object text, you can use a wildcard search like this
select top 100 *
from sys.sql_modules sm
inner join (select searchString = 'insert' union all
select searchString = 'update' union all
select searchString = 'delete') x
on sm.definition like '%' + x.searchString + '%'

Sql query to select records only when count(column)=1

I am trying to retrieve records from oracle 10g express.
I want to execute :
select name|| '=' || id from literals where name='vge_1'
only when count(vge_1) is equal to 1.
else I want to display an error.
I tried following query, but its giving
ORA-00905: missing keyword
THe query I tried is as follows:
select case(name)
when count('vge_1') then (select name|| '=' || id from literals where name='vge_1';)
else Errror
end
from Literals where name='vge_1';
Thanks for your help in advance.
Instead of the case add HAVING count(name)=1 in the end of th query
Try this:
select b.id,a.* from
(select name from Literals
where name='vge_1'
group by name
having count(name)=1)a,Literals b
where b.name=a.name
Try this SQL Fiddle:
select distinct case
when l2.c = 1 then l1.name || '=' || l1.id
else 'Error'
end as name_id
from literals l1,
(
select name, count(name) as c
from literals
where name = 'vge_1'
group by name
having count(name) = 1
) l2
where l1.name = l2.name(+)
and l1.name = 'vge_1'
;
The inner query is roughly same as the other answers. The outer query uses a left outer join (+) to determine if the inner query contains a match for your count() restriction.
Note that you must update the name in two places when running this query.