Error while running very long SQL query with UNION ALL operator in Vertica - sql

This is a sample of subquery used in Vertica Query which is a string generated from the application.
SELECT 1 as ID, 345.45 as PaidAmt FROM DUAL
UNION ALL
SELECT 2 as ID, 789.45 as PaidAmt FROM DUAL
UNION ALL
...
...
There are some cases when this subquery becomes huge as the number of rows with UNION ALL increases. Vertica supports this query to some extent. But when there is let's say 3000 + UNION ALL operator used in a subquery it throws an error.
[SQL Error [4963] [54001]: [Vertica]VJDBC ERROR: The query
contains a SET operation tree that is too complex to analyze
I could not find any documents that talk about the limited use of UNION ALL operator in query or length of the query string.
Is there any system parameter in Vertica or Linux for which we can change the value to successfully execute the query?
I have an alternate approach to fix the query removing UNION ALL. But looking for a solution to the error generated.
Thanks in Advance!

If the CSV option proves impossible, I would use a temporary table - and it would also speed up your query:
CREATE LOCAL TEMPORARY TABLE helper_table(id,paidamt)
ON COMMIT PRESERVE ROWS AS
SELECT 1, 345.45
UNION ALL SELECT 2, 789.45
UNION ALL SELECT 3, 213.44
[.2997 more rows . .]
;
INSERT INTO helper_table
SELECT 3001, 4345.45
UNION ALL SELECT 3002, 3789.45
UNION ALL SELECT 3003, 1213.44
[.2997 more rows . .]
;
SELECT
<<whatever>>
FROM helper_table JOIN <<other_tables>> ON <<whatever>>
;
The helper_table will die as soon as you log off again.
Alternatively, use vsql with a script like this:
CREATE LOCAL TEMPORARY TABLE helper_table (
id INT
, paidamt NUMERIC(9,2)
)
ON COMMIT PRESERVE ROWS;
COPY helper_table FROM stdin;
1| 345.45
2| 789.45
3| 213.44
3001| 4345.45
3002| 3789.45
3003| 1213.44
\.
-- Now you can work with it ...
SELECT * FROM helper_table;

Related

Storing a list of codes into a variable in Oracle SQL [duplicate]

This question already has answers here:
PL/SQL - Use "List" Variable in Where In Clause
(3 answers)
How to load a large number of strings to match with oracle database?
(3 answers)
Closed 10 months ago.
There's a way to store a set of codes into a variable in Oracle SQL?
I have these codes and I'll need to use them in different parts of my query.
But I wouldn't repeat this list in many places in my SQL code.
'G31', 'G310', 'G311', 'G312', 'G318', 'G319', 'G239', 'G122', 'G710',
'B20', 'B22', 'B23', 'B24', 'G35', 'C811', 'G37', 'G375', 'K702', 'K741'
I would like to do something like this idea:
LIST <- ['G31', 'G310', 'G311', 'G312', 'G318', 'G319', 'G239', 'G122', 'G710',
'B20', 'B22', 'B23', 'B24', 'G35', 'C811', 'G37', 'G375', 'K702', 'K741']
SELECT * FROM TABLE_A where COLUMN IN [LIST];
SELECT * FROM TABLE_B where COLUMN IN [LIST];
A fancy approach is this
WITH CODE_VALUES AS
( SELECT DISTINCT COLUMN_VALUE AS CODE_VALUE
FROM TABLE (sys.dbms_debug_vc2coll ('G31',
'G310',
'G311',
'G312',
'G318',
'G319',
'G239',
'G122',
'G710',
'B20',
'B22',
'B23',
'B24',
'G35',
'C811',
'G37',
'G375',
'K702',
'K741'))
)
SELECT *
FROM CODE_VALUES -- + the rest of your query
You could do the same thing with successive union's against "dual" too
WITH CODE_VALUES AS
( SELECT 'ABC' AS code_value FROM dual UNION
SELECT 'CDE' AS code_value FROM dual
)
If this is going to get used across multiple operational queries it's probably best just to store them in a table.
Create a global temporary table once and add the desired values in the gtt and then use it in query using join.
Benifit of gtt is that you don't have to worry about data maintance. (Delete - insert). Data added in one session/transaction will be visible in that session/transaction only (based on type of gtt that you have created.
Create global temporary table gtt
(Col1 varchar2(10))
On commit preserve row; -- session specific
Insert into gtt
Select 'G31' from dual union all
Select 'G310' from dual union all
...
...
Select 'K741' from dual;
Now, you can use it anywhere in the same session as follows:
SELECT *
FROM TABLE_A a
Join gtt g on a.COLUMN = g.col1;
SELECT *
FROM TABLE_B b
Join gtt g on b.COLUMN = g.col1;

How to insert multipleRows in oracle using sequence

I need to insert multiple Rows in oracle database, I use this command line:
INSERT ALL
INTO PHMR_VIP (PHMR_VIP_ID,PHMR_VIP_NOM,PHMR_VIP_PRENOM) VALUES (SQ_PHMR_VIP.nextval, 'dfdf', 'dfdfd')
INTO PHMR_VIP (PHMR_VIP_ID,PHMR_VIP_NOM,PHMR_VIP_PRENOM) VALUES (SQ_PHMR_VIP.nextval, 'ffdf', 'dfdf')
INTO PHMR_VIP (PHMR_VIP_ID,PHMR_VIP_NOM,PHMR_VIP_PRENOM) VALUES (SQ_PHMR_VIP.nextval, 'mohfdfd','fdfdf')
SELECT * FROM dual;
But, I have oracle error:
ORA-00001: violation de contrainte unique (PHMR.PHMR_VIP_PK)
How can I resolve this please? I need to do a bulkInsert with column PHMR_VIP_ID as a sequence
You can use:
INSERT INTO PHMR_VIP (PHMR_VIP_ID,PHMR_VIP_NOM,PHMR_VIP_PRENOM)
SELECT SQ_PHMR_VIP.nextval, col1, col2
FROM (
SELECT 'dfdf' AS col1, 'dfdfd' AS col2 FROM dual
UNION ALL
SELECT 'ffdf', 'dfdf' FROM dual
UNION ALL
SELECT 'mohfdfd','fdfdf' FROM dual
);
For some, you have to use SELECT 1 FROM dual; instead of SELECT * FROM dual;. See this reference: https://community.oracle.com/thread/2457262. This is because there is only 1 row in dual.
That doesn't help in this instance though, because you can't use sequences with SELECT ALL, per this article: https://community.oracle.com/thread/1038439, at least not the way you have. You can if you have a trigger that catches each nextval call and updates the value manually, but as mentioned further in the postings, it can decrease performance.
The recommendation is to use multiple inserts rather than an insert all.
Hope this helps.
-C§

While inserting multiple rows what does the statement 'select 1 from dual' do?

While inserting multiple rows into a table using the following style :
insert all
into ghazal_current (GhazalName,Rating) values('Ajab Apna Haal Hota Jo Visaal-e-Yaar Hota',5)
into ghazal_current (GhazalName,Rating) values('Apne Hothon Par Sajana Chahta Hun',4)
into ghazal_current (GhazalName,Rating) values('Shaam Se Aankh Mein Nami Si Hai',4)
into ghazal_current (GhazalName,Rating) values('Tumhe Yaad Ho Ke Na Yaad Ho',3)
select 1 from dual;
What does the statement select 1 from dual mean ? What is it here for ?
DUAL is a built-in table, useful because it is guaranteed to return only one row. This means DUAL may be used to get pseudo-columns such as user or sysdate, the results of calculations and the like. The owner of DUAL is SYS but it can be accessed by every user. DUAL is well-covered in the documentation. Find out more.
In your case, SELECT 1 FROM DUAL; will simply returns 1. You need it because the INSERT ALL syntax demands a SELECT clause but you are not querying the input values from a table.
Brief re-introduction to one-row tables
Some SQL databases require all values to come FROM a table or table-like object, whereas others permit queries to construct values ex nihilo:
-- MySQL, sqlite, PostgreSQL, HSQLdb, and many others permit
-- a "naked" select:
SELECT 1;
-- Others *require* a FROM target, like Oracle.
SELECT 1 FROM DUAL;
-- ...and Firebird/Interbase:
SELECT 1 FROM RDB$DATABASE;
-- ...and DB2:
SELECT 1 FROM SYSIBM.SYSDUMMY1;
Here the cardinality of DUAL is important. If it had more than one row, your result set would have more than one row. What happens, for example, when you SELECT 1 FROM A_Table_With_Ten_Rows?
Why DUAL is used here
The SQL construct VALUES (<row-value-expression>) is a row value constructor. VALUES (1, 2, 3) "creates" a row of values just as SELECT 1, 2, 3 does.
Oracle, of course, requires that these values come FROM somewhere.
As a demonstration, instead of SELECTing from DUAL at the end of the INSERT ALL, try a table with N rows, and you'll see that each VALUES() row is inserted N times.
There are some samples about using dual in Queries:
select sysdate from dual /--it returns date of system
SELECT chr(223) FROM dual /--it returns character of Asciهi code
select my_sequence.nextval from dual; /-- It returns the next value of a sequence
select to_char(sysdate,'yyyy/mm/dd','nls_calendar=persian')from dual
/--returns persian date of system

return a default row in sql

Is it possible in oracle sql to return a default row if no rows found.
I have a process where in rows fetched will be put in a flat ascii file.
now i have a requirement that if there are no rows fetched by the sql query then there should be a default row in the ascii file.
is it possible in sql to output a default row if no rows fetched by the query
note: i dont want to use pl/sql.
For complex queries where the overhead on finding out if there is a row in the result set is onerous or the query is just very large and unwieldy, then a subquery factoring clause might be beneficial:
With my_query as
(
select a, b, c from foobar where foo='FOO'
)
Select a,b,c
From my_query
Union All
Select ...
From dual
Where Not Exists
(Select 1 from my_query)
/
You could use UNION ALL for this:
select a, b, c from foobar
where foo='FOO'
union all
select 'def', 'ault', 'value' from dual
where not exists ( select 'x' from foobar where foo='FOO' )
I suspect that it would be cleaner to have the process that the writes the ASCII file write the default data if no rows are returned rather than getting Oracle to do it. If the query that you're using is expensive, you'd significantly increase that cost if you fudge it to return a default row as ammoQ and David Oniell have done.
There is another (sad, twisted) option. No CTEs or subquery repetition needed.
select
coalesce(a, 'def'),
coalesce(b, 'ault'),
coalesce(c, 'value')
from foobar
right join (select 1 from dual) on 1=1
where foobar.some_condition;

Oracle Select numbers from an IN clause

I'm looking for the best way to select numbers directly from an in clause.
Basically like:
SELECT * FROM (2,6,1,8);
That doesn't work. I can do it this way:
SELECT Lv FROM ( SELECT Level LV
FROM DUAL
CONNECT BY Level < 20)
WHERE Lv IN (2,6,1,8);
But that seems to be a bit clunky. Is there a more elegant way?
You can do
select column_value from table(sys.dbms_debug_vc2coll(1,2,3,4,5));
but that actually returns a varchar2. You can create your own TYPE and use that
create type tab_num is table of number;
/
select column_value from table(tab_num(1,2,3,4,5));
It's also worth looking at the MODEL clause. It looks complicated, but it is very good at generating data
SELECT x from dual
MODEL DIMENSION BY (1 AS z) MEASURES (1 x)
RULES ITERATE (7) (x[ITERATION_NUMBER]=ITERATION_NUMBER+1)
It's more elegant if you materialize an auxiliary numbers table:
SELECT num FROM numbers WHERE num IN (2,6,1,8);
And this is also useful when combined with another table.
For instance, I've had a case where I needed to populate large configuration tables with changes from piecewise results:
Big SP or Excel sheet or report identifies missing cost centers in config gives a large set of results which need to be inserted with varying data in some groups.
Paste partial results into a individual comma separated lists:
INSERT INTO {stuff}
SELECT {stuff}, 130 as line_item
FROM numbers
WHERE numbers.num IN ({pasted a section of results})
INSERT INTO {stuff}
SELECT {stuff}, 135 as line_item
FROM numbers
WHERE numbers.num IN ({pasted another section of results})
If you don't explicitly need the IN clause, you could use UNION:
select 2 from dual
union
select 6 from dual
union
select 1 from dual
union
select 8 from dual
There is a more elegant variant to INSERT multiple rows into a table:
INSERT ALL
INTO table (col) VALUES ('a')
INTO table (col) VALUES ('b')
INTO table (col) VALUES ('c')
SELECT * FROM dual;
But I don't know a way to do that for a SELECT.