Edit Total line in Oracle report 1 - oracle

The data structure:
sql-> desc t1
- List item
p_code number,
acc_date date ,
debit number,
credit number
Data inside my table:
sql-> select * from t1;
| p_code | acc_date | debit | credit |
| 001 | 01-01-15 | 100 | 25 |
| 001 | 02-01-15 | 0 | 125 |
| 001 | 03-01-15 | 415 | 85 |
I would like to do something like this:
select * from t1
where acc_date between :fromdate and :todate
union all
select p_code, (sum(nvl(debit,0))- sum(nvl(credit,0))) open_balance
from t1
where acc_date < :fromdate
;
But, I can't figure out what are my mistakes.

Type and number of columns in union must be the same -
select p_code, acc_date, debit, credit, null as open_balance
from t1
where acc_date between :fromdate and :todate
union all
select p_code, null as acc_date, null as debit, null as credit,
(sum(nvl(debit, 0)) - sum(nvl(credit, 0))) open_balance
from t1
where acc_date < :fromdate

Related

Vertica - Join on MAX(Date)

I m trying to replicate this sql syntax in Vertica, but it returns "ERROR: Subqueries in the ON clause are not supported".
The aim is to join two tables, table1 and table2, on column and date, if a.date = b.date or the closest but lesser b.date.
Any hint?
SELECT *
FROM table1 a
LEFT JOIN table2 b
ON a.column = b.column
AND b.Date = (SELECT MAX (b2.Date)
FROM table2 b2
WHERE a.column = b2.column
AND b2.Date <= a.Date)
Vertica has something handier for that: the event series join. With that, you can OUTER JOIN two tables so that they match the same or the immediately preceding value of the join column of the other table. The predicate is INTERPOLATE PREVIOUS VALUE instead of an equi-predicate.
Here's an example with the oil pressure curve and the engine rpm curve with the timestamp matching only once.
DROP TABLE IF EXISTS oilpressure;
CREATE TABLE oilpressure (
op_vid,op_ts,op_psi
) AS (
SELECT 42,TIMESTAMP '2020-04-01 07:00:00', 25.356
UNION ALL SELECT 42,TIMESTAMP '2020-04-01 07:00:12', 35.124
UNION ALL SELECT 42,TIMESTAMP '2020-04-01 07:00:23', 47.056
UNION ALL SELECT 42,TIMESTAMP '2020-04-01 07:00:34', 45.225
)
;
DROP TABLE IF EXISTS revspeed;
CREATE TABLE revspeed (
rs_vid,rs_ts,rpm
) AS (
SELECT 42,TIMESTAMP '2020-04-01 07:00:00', 2201
UNION ALL SELECT 42,TIMESTAMP '2020-04-01 07:00:10', 3508
UNION ALL SELECT 42,TIMESTAMP '2020-04-01 07:00:20', 6504
UNION ALL SELECT 42,TIMESTAMP '2020-04-01 07:00:30', 6608
)
;
-- without
\pset null '(null)'
SELECT *
FROM oilpressure
LEFT OUTER JOIN revspeed
ON op_vid=rs_vid AND op_ts=rs_ts ;
-- out Null display is "(null)".
-- out op_vid | op_ts | op_psi | rs_vid | rs_ts | rpm
-- out --------+---------------------+--------+--------+---------------------+--------
-- out 42 | 2020-04-01 07:00:00 | 25.356 | 42 | 2020-04-01 07:00:00 | 2201
-- out 42 | 2020-04-01 07:00:12 | 35.124 | (null) | (null) | (null)
-- out 42 | 2020-04-01 07:00:23 | 47.056 | (null) | (null) | (null)
-- out 42 | 2020-04-01 07:00:34 | 45.225 | (null) | (null) | (null)
-- with
SELECT *
FROM oilpressure
LEFT OUTER JOIN revspeed
ON op_vid=rs_vid AND rs_ts INTERPOLATE PREVIOUS VALUE op_ts;
-- out op_vid | op_ts | op_psi | rs_vid | rs_ts | rpm
-- out --------+---------------------+--------+--------+---------------------+------
-- out 42 | 2020-04-01 07:00:00 | 25.356 | 42 | 2020-04-01 07:00:00 | 2201
-- out 42 | 2020-04-01 07:00:12 | 35.124 | 42 | 2020-04-01 07:00:10 | 3508
-- out 42 | 2020-04-01 07:00:23 | 47.056 | 42 | 2020-04-01 07:00:20 | 6504
-- out 42 | 2020-04-01 07:00:34 | 45.225 | 42 | 2020-04-01 07:00:30 | 6608

Oracle: Taking columns from rows and putting them side by side

I'm having trouble figuring out how to do something in Oracle. I have this table:
| id | rownum | code | gift |
|-----|--------|-----------|------|
|2000 | 1 | Ganymede | 437 |
|2000 | 2 | Alpha | 50 |
|2000 | 3 | Ambergris | 600 |
And the client wants it to look like this:
| id | code_1 | gift_1 | code_2 | gift_2 | code_3 | gift_3 |
|----|--------|--------|--------|--------|-----------|--------|
|2000|Ganymede| 437 | Alpha | 50 | Ambergris | 600 |
I'm not quite sure how to go about doing this using PIVOT.
You can use PIVOT:
SELECT id,
"1_CODE" AS code_1,
"1_GIFT" AS gift_1,
"2_CODE" AS code_2,
"2_GIFT" AS gift_2,
"3_CODE" AS code_3,
"3_GIFT" AS gift_3
FROM table_name
PIVOT (
MAX(code) AS code,
MAX(gift) AS gift
FOR "ROWNUM" IN (1, 2, 3)
)
or conditional aggregation:
SELECT id,
MAX(CASE "ROWNUM" WHEN 1 THEN code END) AS code_1,
MAX(CASE "ROWNUM" WHEN 1 THEN gift END) AS gift_1,
MAX(CASE "ROWNUM" WHEN 2 THEN code END) AS code_2,
MAX(CASE "ROWNUM" WHEN 2 THEN gift END) AS gift_2,
MAX(CASE "ROWNUM" WHEN 3 THEN code END) AS code_3,
MAX(CASE "ROWNUM" WHEN 3 THEN gift END) AS gift_3
FROM table_name
GROUP BY id
Which, for the sample data:
CREATE TABLE table_name (id, "ROWNUM", code, gift ) AS
SELECT 2000, 1, 'Ganymede', 437 FROM DUAL UNION ALL
SELECT 2000, 2, 'Alpha', 50 FROM DUAL UNION ALL
SELECT 2000, 3, 'Ambergris', 600 FROM DUAL;
Both output:
ID
CODE_1
GIFT_1
CODE_2
GIFT_2
CODE_3
GIFT_3
2000
Ganymede
437
Alpha
50
Ambergris
600
db<>fiddle here

A scenario for combining multiple rows in oracle

I have a table with vaues like
MY_ID(NUMBER) COL_1(NUMBER) COL_2(NUMBER) COL_3(VARCHAR2)
11 1001 NULL GT
11 NULL 1002 TG
11 NULL 1003 TG2
12 1004 NULL GT
12 NULL 1006 TG
12 NULL 1005 TG2
My expected result is
MY_ID(NUMBER) COL_1(NUMBER) COL_2(NUMBER) COL_3(VARCHAR2)
11 1001 1003 TG2
12 1004 1006 TG
I can use MAX for numbers, but how about the Varchar2?
How can I combine multiple rows like this?
MAX aggregate functions can be used for varchar too, see this example:
SELECT my_id, max( col_1 ), max( col_2 ), max( col_3 )
FROM Table1
GROUP BY my_id;
Demo: http://sqlfiddle.com/#!4/406e8d7/6
| MY_ID | MAX(COL_1) | MAX(COL_2) | MAX(COL_3) |
|-------|------------|------------|------------|
| 11 | 1001 | 1003 | TG2 |
| 12 | 1004 | 1006 | TG2 |
However, in your question is stated that for the record 12 must be returned value TG instead TG2. I'm guessing that you want to return not the maximum column value of COL_3, but the value from the record for which the maximum value from column COL2 exists. In such a case you can use a query like this:
SELECT my_id, max( col_1 ), max( col_2 ),
max( col_3 ) KEEP (DENSE_RANK LAST ORDER BY col_2 NULLS FIRST)
FROM Table1
GROUP BY my_id;
Demo: http://sqlfiddle.com/#!4/406e8d7/6
| MY_ID | MAX(COL_1) | MAX(COL_2) | MAX(COL_3)KEEP(DENSE_RANKLASTORDERBYCOL_2NULLSFIRST) |
|-------|------------|------------|------------------------------------------------------|
| 11 | 1001 | 1003 | TG2 |
| 12 | 1004 | 1006 | TG |

ORACLE: INSERT SELECT FROM 2 views and value from param

I'm trying to insert some fields into MYTABLE from views MYVIEW1 and MYVIEW2 and then add a value from a parameter (this is part of a stored procedure) for UPDATED_BY, SYSDATE for UPDATED_ON. How can I correctly do this with INSERT SELECT or some other way entirely?
MYVIEW1
+------+----+-----+-----------+---------+
| YR | MO | QTR | USER_CODE | MO_PERF |
+------+----+-----+-----------+---------+
| 2012 | 1 | 1 | 1099 | 89 |
| 2012 | 2 | 1 | 1099 | 86 |
| 2012 | 3 | 1 | 1099 | 95 |
+------+----+-----+-----------+---------+
MYVIEW2
+------+-----+-----------+----------+
| YR | QTR | USER_CODE | QTR_PERF |
+------+-----+-----------+----------+
| 2012 | 1 | 1099 | 90 |
+------+-----+-----------+----------+
MYTABLE
+------+-----+-----------+---------+---------+---------+---------+-------------+------------+
| YR | QTR | USER_CODE | MO1_PCT | MO2_PCT | MO3_PCT | INC | UPDATED_BY | UPDATED_ON |
+------+-----+-----------+---------+---------+---------+---------+-------------+------------+
| 2012 | 1 | 1099 | 89 | 86 | 95 | 7000 | SAMPLE NAME | 01/16/2013 |
+------+-----+-----------+---------+---------+---------+---------+-------------+------------+
INSERT INTO MYTABLE
(YR,QTR,USER_CODE,MO1_PCT,MO2_PCT,MO3_PCT,INC,UPDATED_BY,UPDATED_ON)
SELECT b.YR,b.QTR,b.USER_CODE,b.MO1_PCT,b.MO2_PCT,b.MO3_PCT,c.INC
FROM MYVIEW1 b,
MYVIEW2 c
How do I insert values for (first month of QTR's MO_PERF) as MO1_PCT and (second month of QTR's MO_PERF) as MO2_PCT and (last month of QTR's MO_PERF) as MO3_PCT, making sure that I've inserted the right month within the right quarter and year.And then check if the MO_PERF values of each month has reached at least 85, else set INC as NULL.
,CASE WHEN MO1_PCT>=85 AND MO2_PCT>=85 AND MO3_PCT>=85 THEN 7000
ELSE NULL
END INC
If you're using oracle 11g then you can use PIVOT like this:
select YR, QTR, USER_CODE, "1_MO_PCT" MO1_PCT, "2_MO_PCT" MO2_PCT, "3_MO_PCT" MO3_PCT ,
case when "1_MO_PCT" >= 85 and "2_MO_PCT" >= 85 and "2_MO_PCT" >= 85 then 7000 end INC,
user updated_by, sysdate updated_on
from (
select m1.yr, m1.mo, m1.qtr, m1.user_code, m1.mo_perf, m2.qtr_perf
from myview1 m1 join myview2 m2 on m1.yr=m2.yr
and m1.qtr = m2.qtr and m1.user_code = m2.user_code )t
pivot(
max(mo_perf) MO_PCT for mo in (1,2,3)
)
Here is a sqlfiddle demo

SQL bring back highest sum of rows

I'm looking to calculate the highest basket in my set of data but I can't get my head around how I should do it.
I have data like:
OrderID | CustomerID | BasketID | ProductID | Price
1 | 1 | 1 | 221 | 10
2 | 1 | 1 | 431 | 123
3 | 1 | 2 | 761 | 44
4 | 2 | 3 | 12 | 54
5 | 2 | 3 | 102 | 78
6 | 3 | 4 | 111 | 98
7 | 3 | 4 | 41 | 45
8 | 3 | 5 | 65 | 66
9 | 4 | 6 | 32 | 47
10 | 4 | 6 | 118 | 544
Sorry if it seems quite messy.
But I can easily get the SUM with an obvious
SELECT SUM([Price]), BasketID, CustomerID FROM table
GROUP BY BasketID, CustomerID
But how can I filter the list for only the highest priced Basket ID for that CustomerID
Thanks
You can use a CTE (Common Table Expression) with the ROW_NUMBER function:
;WITH HighestPricePerCustomerAndBasket AS
(
SELECT
ID, UserID, ClassID, SchoolID, Created,
ROW_NUMBER() OVER(PARTITION BY BasketID,CustomerID ORDER BY Price DESC) AS 'RowNum'
FROM dbo.YourTable
)
SELECT
[Price], BasketID, CustomerID
FROM HighestPricePerCustomerAndBasket
WHERE RowNum = 1
This CTE "partitions" your data by BasketID,CustomerID, and for each partition, the ROW_NUMBER function hands out sequential numbers, starting at 1 and ordered by Price DESC - so the first row (highest price) gets RowNum = 1 (for each BasketID,CustomerID "partition") which is what I select from the CTE in the SELECT statement after it.
SELECT *
FROM (SELECT *,
DENSE_RANK() OVER (PARTITION BY CustomerID ORDER BY BasketTotal DESC) AS RNK
FROM (SELECT Sum(Price) AS BasketTotal,
BasketID,
CustomerID
FROM Order a
GROUP BY BasketID,
CustomerID
) a
) b
WHERE RNK = 1
I managed to conjure something up that worked.

Resources