I'm having a trouble with saving multiple rows of a query into single one using CLOB.
I've tried this method suggested at ASK TOM https://asktom.oracle.com/pls/apex/f?p=100:11:::NO::P11_QUESTION_ID:9537158500346658848
but i think i'm lacking some knowledge to properly bind variables of my query.
Could you please help me? or maybe there is another option for this query to be compressed into single row using a CLOB
Here is the query in question
Select '<?xml version="1.0" encoding="UTF-8"?>'||chr(10)||
'<OtherServices ServiceMonth="'|| to_char(framework.dim_calendar_pkg.get_startdate(FRAMEWORK.CTL_Session_Parameters_PKG.Get_BillingPeriod()),'YYYYMM')||'" Source ="CLIENT" UniqueFileID ="ID0000036">' as XML
from dual
union all
select CAST(XML as varchar2(2000)) as XML from (
with CTE as
(SELECT R.BS_TEXT AS BillingDriver
, F.CI_NAME AS Signum
, 1 AS Quantity -- not F.Quantity, as even non-billable should have quantity 1
, CASE WHEN F.QUANTITY=0
THEN 'No'
ELSE 'Yes'
END AS Billable
FROM CLIENT.FACTS F
JOIN CLIENT.DIM_RESOURCEUNITS_VW R ON F.RU_ID = R.RU_ID
WHERE F.BILLINGPERIOD = FRAMEWORK.CTL_Session_Parameters_PKG.Get_BillingPeriod()
AND F.BILLINGPERIOD = F.SERVICEPERIOD
AND F.INPUT_SOURCE IN ('CLIENT_CVS_NONPDV','CLIENT_CVS_PDV','CLIENT_CVS_PV')
)
SELECT
XMLSERIALIZE(document
XMLElement("Service",
XMLForest (C.BillingDriver AS "BillingDriver",
C.Signum AS "Signum",
C.Quantity AS "Quantity",
C.Billable AS "Billable")
)
indent size=2) XML
FROM CTE C)
UNION ALL
Select '</OtherServices>' AS XML from dual;
SELECT '201904' AS ServiceMonth
, 'CLIENT' AS Source
, 'ID0000038' AS UniqueFileID
, 'ViCS_MWPII_user' AS BillingDriver
, VM.SIGNUM AS "Signum-ID"
, 1 AS Quantity
, 'Yes' AS Billable
FROM CLIENT.REF_CVS_VICS_MATRIX_VW VM
WHERE VM.ACCESS_TO_VICS_BASE = 1
AND (VM.ACCESS_TO_VICS_DESTKOP_EMEA = 1 OR VM.ACCESS_TO_VICS_DESTKOP_AMCS = 1 OR VM.ACCESS_TO_VICS_DESTKOP_APAC = 1)
AND EXISTS (SELECT 1 from CLIENT.FACTS F
WHERE F.BILLINGPERIOD = FRAMEWORK.CTL_Session_Parameters_PKG.Get_BillingPeriod()
AND F.BILLINGPERIOD = F.SERVICEPERIOD
AND F.INPUT_SOURCE IN ('CLIENT_MWP2_OPER','CLIENT_MWP2_COMP')
AND UPPER(F.CURRENT_USER) = UPPER(VM.SIGNUM))
UNION ALL
-- Signums with VICS_BASE and one of regional VICS_DESKTOPS, but without user in MWPII
SELECT '201904' AS ServiceMonth
, 'CLIENT' AS Source
, 'ID0000038' AS UniqueFileID
, 'ViCS_PV' AS BillingDriver
, VM.SIGNUM AS "Signum-ID"
, 1 AS Quantity
, 'Yes' AS Billable
FROM CLIENT.REF_CVS_VICS_MATRIX_VW VM
WHERE VM.ACCESS_TO_VICS_BASE = 1
AND (VM.ACCESS_TO_VICS_DESTKOP_EMEA = 1 OR VM.ACCESS_TO_VICS_DESTKOP_AMCS = 1 OR VM.ACCESS_TO_VICS_DESTKOP_APAC = 1)
AND NOT EXISTS (SELECT 1 from CLIENT.FACTS F
WHERE F.BILLINGPERIOD = FRAMEWORK.CTL_Session_Parameters_PKG.Get_BillingPeriod()
AND F.BILLINGPERIOD = F.SERVICEPERIOD
AND F.INPUT_SOURCE IN ('CLIENT_MWP2_OPER','CLIENT_MWP2_COMP')
AND UPPER(F.CURRENT_USER) = UPPER(VM.SIGNUM))
UNION ALL
-- Other signums with VICS_Base =1, but without regional VICS_Desktop
SELECT '201904' AS ServiceMonth
, 'CLIENT' AS Source
, 'ID0000038' AS UniqueFileID
, 'ViCS_Apps' AS BillingDriver
, VM.SIGNUM AS "Signum-ID"
, 1 AS Quantity
, 'Yes' AS Billable
FROM CLIENT.REF_CVS_VICS_MATRIX_VW VM
WHERE VM.ACCESS_TO_VICS_BASE = 1
AND (VM.ACCESS_TO_VICS_DESTKOP_EMEA IS NULL OR VM.ACCESS_TO_VICS_DESTKOP_EMEA != 1)
AND (VM.ACCESS_TO_VICS_DESTKOP_AMCS IS NULL OR VM.ACCESS_TO_VICS_DESTKOP_AMCS != 1)
AND (VM.ACCESS_TO_VICS_DESTKOP_APAC IS NULL OR VM.ACCESS_TO_VICS_DESTKOP_APAC != 1)
Thank you
Here is an example to convert multiple rows of data into a single CLOB value delimited by newline. In the cursor part you may want to replace with your query.
create table test(c clob);
declare
lv_clob CLOB;
cursor c
is select rpad('*',level*2,' *')||chr(10) rec from dual connect by level <= 15;
c_rec varchar2(100);--Holds each record from above cursor in each iteration
begin
dbms_lob.createtemporary(lv_clob, TRUE);
open c;
loop
fetch c into c_rec;
exit when c%notfound;
dbms_lob.append(lv_clob, c_rec);
end loop;
insert into test values(lv_clob);
commit;
dbms_lob.freetemporary(lv_clob);
end;
select * from test;
Output:
C
*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
* * * * * * * *
* * * * * * * * *
* * * * * * * * * *
* * * * * * * * * * *
* * * * * * * * * * * *
* * * * * * * * * * * * *
* * * * * * * * * * * * * *
* * * * * * * * * * * * * * *
I am trying to come up with an SQLite query which would retrieve all the row values between two given values (A and B) in the query,upon meeting a condition.
if (value B given is greater than the maximum value of B in the table):
- retrieve all values between A and B
Sample Table: inventory
Prod_name | model | location |
tesla | "5.6.1" | CA
toyota | "4.7.1" | WA
kia | "6.8.1" | MD
tesla | "2.6.2" | CA
chev | "7.8.4" | AZ
Input given : model between ("5.0.0" to "8.2.0")
Output : (telsa,5.6.1,CA),(kia,6.8.1,MD) , (chev,7.8.4,AZ)
Input given : model between ("5.0.0" to "6.9.0")
Output: Query should not run as "7.8.4" > "6.9.0"
i.e ( the max value in the table is greater than the upper limit of input query.
Also to note is the model name is TEXT format. I need help to retrieving
I have tried "CASE" statements of sqlite but was not able to retrieve
multiple columns in the subquery.
select
case
when (select 1000000 * replace(model, '.', 'x') +
1000 * replace(substr(model, instr(model, '.') + 1), '.', 'x') +
replace(model, '.', '000') % 1000 as md from inventory ORDER BY md
DESC LIMIT 1) > (select 1000000 * replace('5.0.0', '.', 'x') +
1000 * replace(substr('5.0.0', instr('5.0.0', '.') + 1), '.', 'x') +
replace('5.0.0', '.', '000') % 1000)
THEN (select model from inventory where
1000000 * replace(model, '.', 'x') +
1000 * replace(substr(model, instr(model, '.') + 1), '.', 'x') +
replace(model, '.', '000') % 1000
between
1000000 * replace('5.0.0' '.', 'x') +
1000 * replace(substr(''5.0.0'', instr('5.0.0', '.') + 1), '.',
'x') +
replace('5.0.0', '.', '000') % 1000
and
1000000 * replace('8.5.0', '.', 'x') +
1000 * replace(substr('8.5.0', instr('8.5.0', '.') + 1), '.', 'x') +
replace('8.5.0', '.', '000') % 1000 )
END from inventory
I believe that the following will do what you want :-
/* Query using model in n.n.n format */
SELECT * FROM inventory
WHERE
((1000000 * substr(model,1,instr(model,'.')-1)) +
(1000 * replace(substr(model,instr(model,'.') + 1),'.','x')) +
replace(model,'.','000') % 1000)
BETWEEN
(
SELECT 1000000 * substr('5.0.0',1,instr('5.0.0','.') -1)
+ (1000 * replace(substr('5.0.0',instr('5.0.0','.') + 1),'.','x'))
+ replace('5.0.0','.','000') % 1000
)
AND
(
SELECT 1000000 * substr('8.5.0',1,instr('8.5.0','.') -1)
+ (1000 * replace(substr('8.5.0',instr('8.5.0','.') + 1),'.','x'))
+ replace('8.5.0','.','000') % 1000
)
/* MAX COndition */
AND
(
SELECT 1000000 * substr('8.5.0',1,instr('8.5.0','.') -1)
+ (1000 * replace(substr('8.5.0',instr('8.5.0','.') + 1),'.','x'))
+ replace('8.5.0','.','000') % 1000
)
>
(
SELECT MAX(((1000000 * substr(model,1,instr(model,'.')-1))
+ (1000 * replace(substr(model,instr(model,'.') + 1),'.','x'))
+ replace(model,'.','000') % 1000))
FROM inventory
)
ORDER BY
(1000000 * substr(model,1,instr(model,'.')-1)) +
(1000 * replace(substr(model,instr(model,'.') + 1),'.','x')) +
replace(model,'.','000') % 1000
;
I am curious to know how this could be used in the current solution.
Or if you have any other approach ?
I would suggest that you are grossly over-complicating matters by using a model that is formatted as n.n.n.
If you were to convert that model to an integer value matters could be greatly simplified.
If you really want to keep the model as n.n.n then perhaps ALTER the table to add a column that stores the model as an integer. e.g. you could, as a one of, use :-
ALTER TABLE inventory ADD COLUMN model_value INTEGER DEFAULT -1;
This adds the column model_value
The ALTER could be followed by a mass UPDATE to then set the values for existing rows e.g. :-
UPDATE inventory SET model_value =
(1000000 * substr(model,1,instr(model,'.')-1)) +
(1000 * replace(substr(model,instr(model,'.') + 1),'.','x')) +
replace(model,'.','000') % 1000;
To circumvent needing to change the insert and pre-calculate the model_value, you could add an AFTER INSERT TRIGGER e.g. :-
CREATE TRIGGER IF NOT EXISTS inventory_generate_modelvalue AFTER INSERT ON inventory
BEGIN
UPDATE inventory
SET model_value = (1000000 * substr(model,1,instr(model,'.')-1)) +
(1000 * replace(substr(model,instr(model,'.') + 1),'.','x')) +
replace(model,'.','000') % 1000
WHERE model_value < 0 OR model_value IS NULL
;
END;
Note that if you currently use INSERT without specifying the columns, then the insert would have to be adjusted to specify the columns to be used for the insert, OR you could hard code -1 or NULL for the new column.
The query would then be simpler as :-
/* Query using model_value) */
SELECT * FROM inventory
WHERE model_value
BETWEEN
(
SELECT 1000000 * substr('5.0.0',1,instr('5.0.0','.') -1)
+ (1000 * replace(substr('5.0.0',instr('5.0.0','.') + 1),'.','x'))
+ replace('5.0.0','.','000') % 1000
)
AND
(
SELECT 1000000 * substr('8.5.0',1,instr('8.5.0','.') -1)
+ (1000 * replace(substr('8.5.0',instr('8.5.0','.') + 1),'.','x'))
+ replace('8.5.0','.','000') % 1000
)
AND
(
SELECT 1000000 * substr('8.5.0',1,instr('8.5.0','.') -1)
+ (1000 * replace(substr('8.5.0',instr('8.5.0','.') + 1),'.','x'))
+ replace('8.5.0','.','000') % 1000
)
>
(SELECT MAX(model_value) FROM inventory)
ORDER BY model_value
;
If you wanted convert the model value to n.n.n format you could use base this upon :-
SELECT prod_name,
CAST (model_value / 1000000 AS TEXT)
||'.'
|| CAST((model_value % 1000000) / 1000 AS TEXT)
||'.'
||CAST(model_value % 1000 AS TEXT)
AS model,
location
FROM inventory;
Of course if you had a function within your program or used integer values rather than n.n.n then matters would be even simpler.
Testing
The following code was used for testing the above :-
DROP TABLE IF EXISTS inventory;
DROP TRIGGER IF EXISTS inventory_generate_modelvalue;
CREATE TABLE IF NOT EXISTS inventory (prod_name TEXT ,model TEXT,location TEXT);
INSERT INTO inventory VALUES ('tesla','5.6.1','CA'),('toyota','4.7.1','WA'),('kia','6.8.1','MD'),('tesla','2.6.2','CA'),('chev','7.8.4','AZ') ;
/* Add new column for model as an integer value */
ALTER TABLE inventory ADD COLUMN model_value INTEGER DEFAULT -1;
/* Update existing data for new column */
UPDATE inventory SET model_value =
(1000000 * substr(model,1,instr(model,'.')-1)) +
(1000 * replace(substr(model,instr(model,'.') + 1),'.','x')) +
replace(model,'.','000') % 1000;
CREATE TRIGGER IF NOT EXISTS inventory_generate_modelvalue AFTER INSERT ON inventory
BEGIN
UPDATE inventory
SET model_value = (1000000 * substr(model,1,instr(model,'.')-1)) +
(1000 * replace(substr(model,instr(model,'.') + 1),'.','x')) +
replace(model,'.','000') % 1000
WHERE model_value < 0 OR model_value IS NULL
;
END;
-- INSERT INTO inventory VALUES('my new model','5.0.1','AA',null),('another','0.999.999','ZZ',-1);
SELECT * FROM inventory;
/* Query using model in n.n.n format */
SELECT * FROM inventory
WHERE
((1000000 * substr(model,1,instr(model,'.')-1)) +
(1000 * replace(substr(model,instr(model,'.') + 1),'.','x')) +
replace(model,'.','000') % 1000)
BETWEEN
(
SELECT 1000000 * substr('5.0.0',1,instr('5.0.0','.') -1)
+ (1000 * replace(substr('5.0.0',instr('5.0.0','.') + 1),'.','x'))
+ replace('5.0.0','.','000') % 1000
)
AND
(
SELECT 1000000 * substr('8.5.0',1,instr('8.5.0','.') -1)
+ (1000 * replace(substr('8.5.0',instr('8.5.0','.') + 1),'.','x'))
+ replace('8.5.0','.','000') % 1000
)
/* MAX COndition */
AND
(
SELECT 1000000 * substr('8.5.0',1,instr('8.5.0','.') -1)
+ (1000 * replace(substr('8.5.0',instr('8.5.0','.') + 1),'.','x'))
+ replace('8.5.0','.','000') % 1000
)
>
(
SELECT MAX(((1000000 * substr(model,1,instr(model,'.')-1))
+ (1000 * replace(substr(model,instr(model,'.') + 1),'.','x'))
+ replace(model,'.','000') % 1000))
FROM inventory
)
ORDER BY
(1000000 * substr(model,1,instr(model,'.')-1)) +
(1000 * replace(substr(model,instr(model,'.') + 1),'.','x')) +
replace(model,'.','000') % 1000
;
/* Query using model_value) */
SELECT * FROM inventory
WHERE model_value
BETWEEN
(
SELECT 1000000 * substr('5.0.0',1,instr('5.0.0','.') -1)
+ (1000 * replace(substr('5.0.0',instr('5.0.0','.') + 1),'.','x'))
+ replace('5.0.0','.','000') % 1000
)
AND
(
SELECT 1000000 * substr('8.5.0',1,instr('8.5.0','.') -1)
+ (1000 * replace(substr('8.5.0',instr('8.5.0','.') + 1),'.','x'))
+ replace('8.5.0','.','000') % 1000
)
AND
(
SELECT 1000000 * substr('8.5.0',1,instr('8.5.0','.') -1)
+ (1000 * replace(substr('8.5.0',instr('8.5.0','.') + 1),'.','x'))
+ replace('8.5.0','.','000') % 1000
)
>
(SELECT MAX(model_value) FROM inventory)
ORDER BY model_value
;
SELECT prod_name,
CAST (model_value / 1000000 AS TEXT)
||'.'
|| CAST((model_value % 1000000) / 1000 AS TEXT)
||'.'
||CAST(model_value % 1000 AS TEXT)
AS model,
location
FROM inventory;
Is it practically possible to create a triangle of stars like this as below in SQL.I know that this could be done easily in any other programming language like C,C++,Java but want to know whether it is really possible with just SQL or PL/SQL.I tried working on it with dual table in Oracle but couldn't get through it.
* *
* * * *
* * * or * * *
Can someone please shed somelight if anyone knows about it.
The simplest approach would be something like this. You can get more sophisticated particularly if you want to build the equilateral triangle rather than the right triangle.
SQL> ed
Wrote file afiedt.buf
1 select rpad( '* ', level*2, '* ' )
2 from dual
3* connect by level <= 3
SQL> /
RPAD('*',LEVEL*2,'*')
--------------------------------------------------------------------------------
*
* *
* * *
select rpad('* ', level * 2, '* ')
from dual connect by
level <= 10
*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
* * * * * * * *
* * * * * * * * *
* * * * * * * * * *
select rpad(' ',r*2,' ')||rpad('* ',l*2,'* ') k
from ( select level l,row_number() over(order by null) r
from dual
connect by level<=10
order by l desc)
* * * * * * * * * *
* * * * * * * * *
* * * * * * * *
* * * * * * *
* * * * * *
* * * * *
* * * *
* * *
* *
*
select rpad(' ',l*2,' ')||rpad('* ',r*2,'* ') k
from ( select level l,row_number() over(order by null) r
from dual
connect by level<=10
order by l desc)
*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
* * * * * * * *
* * * * * * * * *
* * * * * * * * * *
select rpad(' ',l,' ')||rpad('* ',r*2,'* ') k
from ( select level l,row_number() over(order by null) r
from dual
connect by level<=10
order by l desc)
*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
Not sure what you are looking for exactly. Perhaps this?
select '*' from dual
union all select '**' from dual
union all select '***' from dual
Example
Here is the script to Get a perfect triangle or Pyramid in sql (tested in Microsoft Sql 2008)
declare #x int,#y int
select #x=5,#y=0
while #x>0
begin
print space(#x)+replicate('*',#y)+replicate('*',#y+1)
set #y=#y+1
set #x=#x-1
end
*
***
*****
*******
*********
you can get many more scripts and help at this link... it was helpful to me
Link:- sqlquerynscript
Try this..
declare #x int,#y int,#diff int
select #x=0,#y=10,#diff=2--diferrence between consecutive rows
while #x<#y
begin
if #x=0 and #diff<>1
print space((#y-#x)*#diff-1)+replicate('*',1)
else if(#diff%2=0)
print space((#y-#x)*#diff)+replicate('* ',#x+(#x*(#diff-1)))
else
print space((#y-#x)*#diff)+replicate('* ',#x+(#x*(#diff-1)))
select #x=#x+1
end
If all you want is the simple triangle, then you can do this:
SELECT '*' FROM table
UNION
SELECT '**' FROM table
UNION
SELECT '***' FROM table
declare #count int,#num int,#num1 int, #space int, #str varchar(50)
set #count = 5 set #num = 1
while(#num<=#count)
begin
set #num1 = 0 set #space = #count-#num
while (#num1<#num)
begin
if #str is null
set #str = '* '
else
set #str = #str+'* ' set #num1 = #num1+1
end
print (space(#space)+#str)
set #num = #num+1 set #str = null
end
[Equilateral Traingle] We can make a pyramid with Oracle SQL as follows.
select rpad(' ',5 -level) || rpad( '* ', level*2, '* ' )
from dual
connect by level <= 5;
** Here 5 is the number of lines.
Let us reverse it,
select rpad(' ',level) || rpad( '* ', 2*(5-level+1), '* ' )
from dual
connect by level <= 5;
declare #row int = 5,
#index int = 0,
#string nvarchar(5) =''
while #row > 0
begin
set #index = #row
while #index > 0
begin
set #string = '*' + #string
set #index = #index - 1
end
print #string
set #string = ''
set #row = #row - 1
end
*****
****
***
**
*
DECLARE #lclMaxLevel INT=5
DECLARE #lclPrintCount INT =0
WHILE #lclMaxLevel > 0
BEGIN
PRINT Space(#lclMaxLevel)
+ Replicate('*', #lclPrintCount+1)
SET #lclMaxLevel=#lclMaxLevel - 1
SET #lclPrintCount=#lclPrintCount + 1
END