Reusing alias for an expression in postgresql - sql

I am trying to do this:
select first_name || ' ' || last_name as full_name, Length(full_name) as len from customer order by len
It is not possible;
column "full_name" does not exist
So, I have to do this:
select first_name || ' ' || last_name as full_name, Length(first_name || ' ' || last_name) as len from customer order by len
Does it mean sql engine has to compute expression 'first_name || ' ' || last_name' two times?

As you observe, what you want to do is not possible. Instead, you can use a lateral join to calculate values in the FROM clause:
select v.full_name, Length(v.full_name) as len
from customer c cross join lateral
(values (first_name || ' ' || last_name)
) v(full_name)
order by len;

Related

Oracle SQL: Alternative to aggregate large texts (when exceeding Listagg limit)

I have a simple Select query that aggregates one column containing large texts.
The following worked for me with small texts but I am now exceeding the Listagg character limit (4000 bytes ?).
I am very new to Oracle and couldn't find a proper solution for this online that I could apply here.
Can someone tell me the best alternative to this ?
My Query (simplified):
SELECT
m.S_ID AS SID
, LISTAGG
(
'ITEM NO.: ' || m.ITEM ||
' -nl-ARTICLE: ' || a.ARTICLE ||
' -nl-NET: ' || m.NET ||
' -nl-TAX: ' || NVL(m.TAX, 0) ||
' -nl-GROSS: ' || (m.NET + m.TAX),
' -nl--nl-'
) WITHIN GROUP (ORDER BY m.S_ID) AS Details
/* ... */
FROM
myTable m
/* ... */
Many thanks for any help with this,
Mike
One of possible method.
select xmlagg(xmlelement(xxx,'ITEM NO.: ' || m.ITEM ||
' -nl-ARTICLE: ' || a.ARTICLE ||
' -nl-NET: ' || m.NET ||
' -nl-TAX: ' || NVL(m.TAX, 0) ||
' -nl-GROSS: ' || (m.NET + m.TAX),
' -nl--nl-'||',<-separator').extract('//text()') order m.S_ID).getClobval() from mytable
group by ...
2nd method.
oracle allows to creat own aggregation function user defined aggregation function

Refactor sql query that uses PostGIS functions

I have a query that looks like this:
SELECT *,
ST_Distance(
ST_GeographyFromText('SRID=4326;POINT(' || users.longitude || ' ' || users.latitude || ')'),
ST_GeographyFromText('SRID=4326;POINT(-84.334078 45.273343)')) as distance
FROM users
WHERE ST_DWithin(
ST_GeographyFromText('SRID=4326;POINT(' || users.longitude || ' ' || users.latitude || ')'),
ST_GeographyFromText('SRID=4326;POINT(-84.334078 45.273343)'),
2000
)
ORDER BY distance ASC;"
I've see some repetitions here. I'm wondering is there any way to make this query more readable?
Lateral join:
select *, ST_Distance(a, b) distance
from
users,
ST_GeographyFromText('SRID=4326;POINT(' || users.longitude || ' ' || users.latitude || ')') a,
ST_GeographyFromText('SRID=4326;POINT(-84.334078 45.273343)') b
where ST_DWithin(a, b, 2000)
order by distance asc;

SQL scripts to generate SQL scripts

Assume that the DBA_TAB_COLUMNS looks like this:
I'd like to write a SQL or PL/SQL script to generate following text:
select 'NULL' as A1, B1, QUERY, RECORD_KEY from SMHIST.probsummarym1
union all
select 'NULL' as A1, 'NULL' as B1, QUERY, RECORD_KEY from SMHIST_EIT200.probsummarym1
union all
select A1, 'NULL' as B1, QUERY, RECORD_KEY from SMHIST_EIT300.probsummarym1
the requirements are:
If the table under any of the SMHIST% schemas do not have that column, then insert a default NULL alias for that columns.
the column list is in alphabetical order.
so can anybody tell me how to write this script?
EDIT: Added better alias names and en explicit CROSS JOIN. Added XMLAGG version.
NB: LISTAGG exists from Oracle version 11.2 and onwards and returns VARCHAR2. If the output string is larger than 4000K or if on a prior version you can use XMLAGG which is a bit more cumbersome to work with (eg. http://psoug.org/definition/xmlagg.htm).
With LISTAGG (returning VARCHAR2):
SELECT LISTAGG (line,
CHR (13) || CHR (10) || 'union all' || CHR (13) || CHR (10))
WITHIN GROUP (ORDER BY sortorder)
script
FROM (SELECT line, ROWNUM sortorder
FROM ( SELECT 'select '
|| LISTAGG (
CASE
WHEN tc.column_name IS NULL
THEN
'''NULL'' as '
END
|| col_join.column_name,
', ')
WITHIN GROUP (ORDER BY col_join.column_name)
|| ' from '
|| col_join.owner
|| '.'
|| col_join.table_name
line
FROM dba_tab_columns tc
RIGHT OUTER JOIN
(SELECT DISTINCT
owner, table_name, col_list.column_name
FROM dba_tab_columns
CROSS JOIN
(SELECT DISTINCT column_name
FROM dba_tab_columns
WHERE owner LIKE 'SMHIST%') col_list
WHERE owner LIKE 'SMHIST%') col_join
ON tc.owner = col_join.owner
AND tc.table_name = col_join.table_name
AND tc.column_name = col_join.column_name
GROUP BY col_join.owner, col_join.table_name
ORDER BY col_join.owner, col_join.table_name))
With XMLAGG (returning CLOB by adding .getclobval (), note: RTRIM works here because table names cannot include ',' and ' ' (space)):
SELECT REPLACE (SUBSTR (script, 1, LENGTH (script) - 12),
'&' || 'apos;',
'''')
FROM (SELECT XMLAGG (
XMLELEMENT (
e,
line,
CHR (13)
|| CHR (10)
|| 'union all'
|| CHR (13)
|| CHR (10))).EXTRACT ('//text()').getclobval ()
script
FROM (SELECT line, ROWNUM sortorder
FROM ( SELECT 'select '
|| RTRIM (
REPLACE (
XMLAGG (XMLELEMENT (
e,
CASE
WHEN tc.column_name
IS NULL
THEN
'''NULL'' as '
END
|| col_join.column_name,
', ') ORDER BY
col_join.column_name).EXTRACT (
'//text()').getclobval (),
'&' || 'apos;',
''''),
', ')
|| ' from '
|| col_join.owner
|| '.'
|| col_join.table_name
line
FROM dba_tab_columns tc
RIGHT OUTER JOIN
(SELECT DISTINCT
owner,
table_name,
col_list.column_name
FROM dba_tab_columns
CROSS JOIN
(SELECT DISTINCT column_name
FROM dba_tab_columns
WHERE owner LIKE 'SMHIST%') col_list
WHERE owner LIKE 'SMHIST%') col_join
ON tc.owner = col_join.owner
AND tc.table_name = col_join.table_name
AND tc.column_name = col_join.column_name
GROUP BY col_join.owner, col_join.table_name
ORDER BY col_join.owner, col_join.table_name)))

Trying To Select A Foreign Key Column Using Concatenation Operator

I have been trying to select all columns from one table into a single column. The problem is I can't seem to get the foreign key "department_id" to show up. If I run this code:
select employee_id || ',' || ' ' || last_name || ',' || ' ' || job_id || ',' || ' ' ||TO_CHAR(hire_date, 'DD Mon YY' ) || ',' || ' '|| department_id
AS "The_Output"
FROM employee;
The information from the "department_id" simply doesn't show. While this code:
select employee_id || ',' || ' ' || last_name || ',' || ' ' || job_id || ',' || ' ' ||TO_CHAR(hire_date, 'DD Mon YY' ) || ',' || ' '|| department_id
AS "The_Output"
FROM employee, department;
gives me this error:
ORA-00918: column ambiguously defined
I have tried to UNION them but that didn't work
That is because department_id exists in both employee and department table. So use alias while selecting.
Also your query is missing the join condition, so you will get cartesian product from both tables. Use something like below.
SELECT E.EMPLOYEE_ID || ',' || ' ' || E.LAST_NAME || ',' || ' ' || E.JOB_ID || ',' || ' ' ||TO_CHAR(E.HIRE_DATE, 'DD Mon YY' ) || ',' || ' '|| E.DEPARTMENT_ID
AS "The_Output"
FROM EMPLOYEE E INNER JOIN DEPARTMENT D
ON E.DEPARTMENT_ID=D.DEPARTMENT_ID

SQL join column

I have a set of table as following
customer(cus_id,cus_first_name,cus_last_name);
insert into customer values ('c001', 'tan', 'wah khang');
I want to create a select statement to display the first name join with the last name.
Example :
tan wah khang
is that possible?
You can use the (this is not called "join" but) concatenation *|| (double pipe)* operator:
SELECT (cus_first_name || ' ' || cus_last_name) AS full_name
FROM customer
|| isn't quite equivalent to MySQL's CONCAT_WS. CONCAT_WS eliminates the delimiter if one of the operands is NULL. So if firstname is NULL and lastname is 'Smith', in MySQL:
CONCAT_WS(' ', firstname, lastname) returns "Smith"
whereas, in Oracle:
firstname || ' ' || lastname returns " Smith" (prepended with a space)
I'd love to know if there's a true equivalent, or if you'd have to write a stored procedure to emulate CONCAT_WS. It's terribly useful.
select cus_first_name || ' ' || cus_last_name from customer
Yes:
select cus_first || ' ' || cus_last from your_table;
In Oracle, PostgreSQL, DB2, Informix:
select cus_first_name || ' ' || cus_last_name from customer
In SQL-Server:
select cus_first_name + ' ' + cus_last_name from customer
In MS-Access:
select cus_first_name & ' ' & cus_last_name from customer
In MySQL:
select concat(cus_first_name , ' ', cus_last_name) from customer
In Informix:
select concatenate(cus_first_name,concatenate(' ',cus_last_name)) from customer