How to query for a built string select - sql

I would like to do something like
SELECT * FROM (
SELECT ('reword#' || reword) || reword_faq as reword FROM me_review_entries re
) as re
WHERE re.reword = 'reword#2#SOME_FAQ'
I tried to do
SELECT ('reword#' || reword) || reword_faq as foo FROM me_review_entries re
WHERE foo = 'reword#2#SOME_FAQ'
But I get:
ERROR: column "foo" does not exist
LINE 2: WHERE foo = 'reword#2#SOME_FAQ'
Is the first way of doing the only way ? Or could I improve that ?

I think it depends on your database, but the foo column does not exist except within the query, so you might have to do:
SELECT ('reword#' || reword) || reword_faq as foo FROM me_review_entries re
WHERE ('reword#' || reword) || reword_faq = 'reword#2#SOME_FAQ'

Related

Can i use group_concat inside another group_concat in SQL?

So i have a query like this:
select
p.identifier,
GROUP_CONCAT(
'[' ||
'{"thumbnail":' ||
'"' ||
ifnull(s.thumbnail,'null') ||
'"' ||
',"title:' ||
'"' ||
s.title ||
'","content": [' ||
GROUP_CONCAT(
'{"text":' ||
ifnull(c.text,'null') ||
'", "image":' ||
ifnull(c.image,'null') ||
'", "caption": "' ||
ifnull(c.caption,'null') ||
'"},'
) ||
']},'
)
from pois as p
join stories as s on p.identifier = s.poiid
join content c on s.storyid = c.storyid
group by s.storyid
And i got and error:
in prepare, misuse of aggregate function GROUP_CONCAT()
To see clearly i have a big object named POIS every POI have multiple STORIES and every STORY have multiple CONTENTS, and i want to display x rows(how many pois i have) and inside the column have every story that is connected to their poi(and every content inside stories) and i need this in json format so i can parse the database query and read back into my object.
I hope its clear what is my problem and you can help me.
So i changed the query to something like this:
SELECT p.identifier, (
SELECT json_group_array(json_object('id', s.storyid))
FROM stories AS s
WHERE s.poiid=p.identifier
) as stories,
(
SELECT json_group_array(json_object('id', c.contentid, 'storyId', s.storyid))
FROM content AS c
JOIN stories AS s ON c.storyid=s.storyid
WHERE s.poiid=p.identifier
) as contents
FROM pois AS p
GROUP BY p.identifier
this is my result:
enter image description here
but the 3 rd column i would like to put inside the second(every pois have multiple stories and every story have one or multiple contents, so the contents should be inside their stories.

REGEXP gives different outputs

I've used REGEXP to find text patterns, but I'm having a problem with one part of it. I'd like to classify a ticketing fare calculation line as having only 1 of the following labels:
blank (there are no Q surcharges)
QCPN (there are only instance(s) of the existing format Q20.00)
QPRO (there are only instance(s) of the new additional format Q LONSYD20.00)
QBOTH (there are examples of both QCPN and QBOTH)
Below SQL:
SELECT JOUR.JOUR_FSERNR
AS TICKET,
CASE
WHEN REGEXP_LIKE (
JOUR.JOUR_FCA1LN
|| JOUR.JOUR_FCA2LN
|| JOUR.JOUR_FCA3LN
|| JOUR.JOUR_FCA4LN,
'Q[[:space:]][[:alpha:]]{6}')
THEN
'QPRO'
WHEN REGEXP_LIKE (
JOUR.JOUR_FCA1LN
|| JOUR.JOUR_FCA2LN
|| JOUR.JOUR_FCA3LN
|| JOUR.JOUR_FCA4LN,
'Q[[:digit:]]+\.[[:digit:]]+.*END')
THEN
'QCPN'
WHEN REGEXP_LIKE (
JOUR.JOUR_FCA1LN
|| JOUR.JOUR_FCA2LN
|| JOUR.JOUR_FCA3LN
|| JOUR.JOUR_FCA4LN,
'Q[[:space:]][[:alpha:]]{6}')
AND REGEXP_LIKE (
JOUR.JOUR_FCA1LN
|| JOUR.JOUR_FCA2LN
|| JOUR.JOUR_FCA3LN
|| JOUR.JOUR_FCA4LN,
'[[ALPHA]]{3}Q[[:digit:]]+\.[[:digit:]]')
THEN
'QBOTH'
ELSE
NULL
END
AS QTYPE,
( (JOUR.JOUR_FCA1LN || JOUR.JOUR_FCA2LN) || JOUR.JOUR_FCA3LN)
|| JOUR.JOUR_FCA4LN
AS FARECALC
FROM "S00BJOUR" JOUR
WHERE JOUR.JOUR_FSERNR = '9999889652'
If you look at the above SQL and find the CASE WHEN line that outputs 'QCPN', you'll see there's an "END" text string 'Q[[:digit:]][[:graph:]]END'. I put ‘END’ in there because I only want the REGEXP to look to the left of 'END' in a fare calc line.
But it gives me some incorrect outputs as shown in the attached image Incorrect Outputs in RED:
Any help to have this corrected is much appreciated.
It feels strange, you don't put so much quantifier. Like QCPN, whathever it means shoudld be :
Q[[:digit:]]{2}\.[[:digit:]]{2}
To match your Q20.00 example at least.
EDIT :
In your "with end exemple", didnt work because you dont put any quantifier :
Q[[:digit:]][[:graph:]]END
#Match Q5.END, Q22END, Q8AEND
#Dont match Q20.00 END
But :
Q[[:digit:]]+\.[[:digit:]]+.*END
#Match "Q1.2 ZA VD END Q20.2"
#Dont match "Q5.END", "BF END Q10.25"
For the second problem, QPRO/QBOTH, the probleme is :
Q HAMAOQ20.00
Try
[[:space:]]Q[[:digit:]]+\.[[:digit:]]+.
For QCPN regex.

Oracle SQL: Using CHR() function with || concatenate and join

Query below returns error
SELECT 'mailto:'|| fscp.parameter_value || '?subject=' || wfn.subject nid_subject || chr(38)
FROM apps.wf_notifications wfn, apps.fnd_svc_comp_param_vals_v fscp
WHERE fscp.component_id = :component_id
AND component_parameter_id = :param
AND wfn.item_key = :itemkey;
Error
ORA-00923: FROM keyword not found where expected
00923.00000 - "FROM keyword not found where expected"
When I remove the '|| chr(38)' at the end of the select statement, the query runs fine.
Something related to joining tables? Because the below query also works fine:
select 'Text: '||chr(39)||wfn.notification_id||chr(39) from wf_notifications wfn;
You have this in the select:
|| wfn.subject nid_subject ||
Perhaps you intend:
SELECT 'mailto:'|| fscp.parameter_value || '?subject=' || wfn.subject || nid_subject || chr(38)
----------------------------------------------------------------------^
Alex is right. The key in the question is that it works without chr(38). So, try this:
SELECT ('mailto:'|| fscp.parameter_value || '?subject=' || wfn.subject || chr(38) ) as nid_subject
Notice the use of parentheses and as to make it clear that a column alias is being defined.

multiple IS NOT NULL with OR operator

Does anyone know how to improve the below oracle sql query with multiple IS NOT NULL with OR operator:
select count(1)
from s_srv_req sr, s_evt_act act, s_bu bu
where sr.row_id = act.sra_sr_id(+)
and sr.bu_id = bu.row_id
and sr.last_upd > to_date('31-DEC-2013','DD-MON-YYYY')
and **(X_REASON_CODE1 is not null
OR X_REASON_CODE2 is not null
OR X_CONCERN_CODE1 is not null
OR X_CONCERN_CODE2 is not null
OR X_COMPONENT_CODE is not null)**
The purpose here is to fetch all records even if one of the codes column is not null.
Note: This query is taking much time and i cannot progress with such time taking queries. Thanks in advance.
You should use COALESCE function
select count(1)
from s_srv_req sr, s_evt_act act, s_bu bu
where sr.row_id = act.sra_sr_id(+)
and sr.bu_id = bu.row_id
and sr.last_upd > to_date('31-DEC-2013','DD-MON-YYYY')
and COALESCE(X_REASON_CODE1, X_REASON_CODE2, X_CONCERN_CODE1, X_CONCERN_CODE2, X_COMPONENT_CODE) is not null
have you tried with using a excluding method?
Use the total table to minus the records that all of those columns are null at the same time?
here are some fake code:
Method1, using Minus
table a
minus
table a with X_REASON_CODE1 ||
OR X_REASON_CODE2 ||
OR X_CONCERN_CODE1 ||
OR X_CONCERN_CODE2 ||
OR X_COMPONENT_CODE is not null
Method 2, using NOT EXISTS or NOT IN
table a
not exists X_REASON_CODE1 ||
OR X_REASON_CODE2 ||
OR X_CONCERN_CODE1 ||
OR X_CONCERN_CODE2 ||
OR X_COMPONENT_CODE is not null

Postgres SELECT a concat field and ILIKE it in Rails

Pretty simple, trying to do this
SELECT (artist_name || ' ' || name) as full_name FROM "songs" WHERE "songs"."working" = 't' AND (full_name ILIKE('%Jack Beats%')) AND (full_name ILIKE('%Epidemic%')) AND (full_name ILIKE('%Dillon Francis%')) ORDER BY songs.published_at asc LIMIT 1
But I get
ActiveRecord::StatementInvalid: PG::Error: ERROR: column "full_name" does not exist
I've tried adding the table name before the stations with no effect.
As sub_stantial mentions in the comments, you can't reference an alias from a SELECT in your WHERE clause. You can use a derived table as dwurf suggests but derived tables in Rails are a bit messy. You could expand your concatenation inside your WHERE instead:
Song.where(:working => true)
.where("artist_name || ' ' || name ILIKE ?", '%Jack Beats%')
.where("artist_name || ' ' || name ILIKE ?", '%Epidemic%')
.where("artist_name || ' ' || name ILIKE ?", '%Dillon Francis%')
.order('songs.published_at asc')
.limit(1)
And if you're doing this sort of thing a lot, a named scope might be useful:
class Song < ActiveRecord::Base
#...
def self.full_name_like(name)
where("artist_name || ' ' || name ILIKE ?", "%#{name}%")
end
end
and then:
Song.where(:working => true)
.full_name_like('Jack Beats')
.full_name_like('Epidemic')
.full_name_like('Dillon Francis')
.order('songs.published_at asc')
.limit(1)
If your application is going to be doing a lot of ILIKE searches like this then you might want to look into a full-text search system: LIKE queries lead to table scans and table scans lead to sadness.
You can't reference a column alias in a where clause. The correct way to write this query is:
SELECT
(artist_name || ' ' || name) AS full_name
FROM "songs"
WHERE "songs"."working" = 't'
AND ((artist_name || ' ' || name) ILIKE('%Jack Beats%'))
AND ((artist_name || ' ' || name) ILIKE('%Epidemic%'))
AND ((artist_name || ' ' || name) ILIKE('%Dillon Francis%'))
ORDER BY songs.published_at ASC
limit 1
;
sub_stantial's approach would look more like this:
select full_name
from (
SELECT
(artist_name || ' ' || name) AS full_name
FROM "songs"
WHERE "songs"."working" = 't'
ORDER BY songs.published_at ASC
)
WHERE (full_name ILIKE('%Jack Beats%'))
AND (full_name ILIKE('%Epidemic%'))
AND (full_name ILIKE('%Dillon Francis%'))
LIMIT 1
;
Performance of these two queries is about the same (pretty rubbish) as they both have to do a full table scan to build the full_name column then sort the results. You might be able to add an index to "working" to speed up these queries.
Here's an sql fiddle in postgresql
Programatic Arel version
NOTE: This has not been fully tested for SQL injection.
class ApplicationRecord < ActiveRecord::Base
scope :fields_sentence_ilike, -> (*fields, term) {
sanitized_term = connection.quote("%#{term}%")
# InfixOperation.new(operator, left, right) => left operator right => concatenated_fiels ILIKE '%word%'
# NamedFunction.new(name, expression_nodes) => name(node0, node1, ...nodeN) => CONCAT_WS("columnA", "columnB", "columnC")
where(
Arel::Nodes::InfixOperation.new(
Arel::Nodes::SqlLiteral.new('ILIKE'),
Arel::Nodes::NamedFunction.new(
'CONCAT_WS', # CONCAT_WS concatenates strings using the first argument. In this case, an empty space.
[
Arel::Nodes::SqlLiteral.new("' '"), # CONCAT by empty space
*fields.map { |field|
# CONCATING any NULL fields results NULL (like multiplying any number by 0 equals 0). COALESCE to empty string.
Arel::Nodes::NamedFunction.new('COALESCE', [arel_attribute(field), Arel::Nodes::SqlLiteral.new("''")])
}
]
),
Arel::Nodes::SqlLiteral.new(sanitized_term)
)
)
}
end
Then a specific implementation for your Songs model
class Song < ApplicationRecord
scope :full_name_like, -> (full_name) { fields_sentence_ilike(:artist_name, :name, full_name) }
end
Usage
Song.full_name_like('Jack Beats')
.full_name_like('Epidemic')
.full_name_like('Dillon Francis')