How to "flatten" the structure with the TABLE expression - sql

I have a VARRAYS TYPE wanted to "flatten" the structure with the TABLE expression.
The example data
CREATE OR REPLACE TYPE ARIS.NUMBER_VARRAY_5 AS VARRAY (5) OF NUMBER NOT NULL;
CREATE TABLE ARIS.TEST_2
(
DATE_START DATE,
DATE_END DATE,
O3 ARIS.NUMBER_VARRAY_5,
CATEGORY NUMBER
)
SET DEFINE OFF;
Insert into TEST_2
(DATE_START, DATE_END, O3, CATEGORY)
Values
(TO_DATE('01/01/2005 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('01/05/2005 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), NUMBER_VARRAY_5(281.25,-9999,291.5,310.5,298.75), NULL);
Insert into TEST_2
(DATE_START, DATE_END, O3, CATEGORY)
Values
(TO_DATE('01/02/2005 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('01/06/2005 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), NUMBER_VARRAY_5(-9999,291.5,310.5,298.75,300.75), NULL);
COMMIT;
using the SQL statement
select O3.* from test_2 t, table(t.o3) O3
I can get the result
COLUMN_VALUE
281.25
-9999
291.5
310.5
298.75
-9999
291.5
310.5
298.75
300.75
The question is how I get the results like
DATE_START DATE_END 03.VALUE1 03.VALUE2 03.VALUE3 03.VALUE4 03.VALUE5
01/01/2005 01/05/2005 281.25 -9999 291.5 310.5 298.75
01/02/2005 01/06/2005 -9999 291.5 310.5 298.75 300.75

Try This,
SELECT
*
FROM
(
select
t.Date_start,
t.Date_end,
row_number() OVER ( PARTITION BY DATE_START, DATE_END
ORDER BY
ROWNUM) rn,
O3.*
from
test_2 t,
table(t.o3) O3
)
PIVOT ( MAX(column_value) FOR rn in
(
1 as "03.VALUE1",
2 as "03.VALUE2",
3 as "03.VALUE3",
4 as "03.VALUE4",
5 as "03.VALUE5"
)
) ;

Related

Best way to get high value of partition from oracle database?

Best way to get high value of partition from oracle database?
"Best" is subjective but you can retrieve the high values by quering the data dictionary:
SELECT partition_name,
high_value
FROM USER_TAB_PARTITIONS
WHERE table_name = 'YOUR_TABLE_NAME';
One way is to use XML
create table t (
x date
) partition by range (x) (
partition p0 values less than (date'2015-01-01'),
partition p1 values less than (date'2015-06-01'),
partition pmax values less than (maxvalue)
);
with xml as (
select dbms_xmlgen.getxmltype('select table_name, partition_name, high_value from user_tab_partitions where table_name = ''T''') as x
from dual
)
select extractValue(rws.object_value, '/ROW/TABLE_NAME') table_name,
extractValue(rws.object_value, '/ROW/PARTITION_NAME') partition,
extractValue(rws.object_value, '/ROW/HIGH_VALUE') high_value
from xml x,
table(xmlsequence(extract(x.x, '/ROWSET/ROW'))) rws;
TABLE_NAME PARTITION HIGH_VALUE
---------- ---------- ------------------------------------------------------------------------------------------
T P0 TO_DATE(' 2015-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
T P1 TO_DATE(' 2015-06-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
T PMAX MAXVALUE

Use value of previous column in the SQL insert query

I am trying following query to insert data from a file. How do I calculate TOTAL_HOURS from in_date and out_date? I know we can not select them as "as in_date" and use it later. It was for illustration purpose only.
The script is reading data from a file and it is not stored in database yet.
insert into Table_A (
Id,
IN_DATE,
OUT_DATE,
TOTAL_HOURS,
)
values (
1,
'2021-10-04 07:00:00' as in_date,
'2021-10-04 07:00:00' as out_date,
DATEDIFF(second, out_date, in_date) / 3600.0
);
If you want to INSERT a static datetime using TIMESTAMPDIFF:
INSERT INTO Table_A (Id, IN_DATE, OUT_DATE, TOTAL_HOURS)
SELECT 1, '2021-10-04 07:00:00', '2021-10-04 08:00:00',
TIMESTAMPDIFF(HOUR, '2021-10-04 07:00:00', '2021-10-04 08:00:00')
If you want to INSERT a dynamic datetime using data from another table (i.e. Table_B to Table_A using a key):
INSERT INTO Table_A (Id, IN_DATE, OUT_DATE, TOTAL_HOURS)
SELECT Id, IN_DATE, OUT_DATE,
TIMESTAMPDIFF(HOUR, IN_DATE, OUT_DATE) FROM Table_B WHERE Id = 1
Result:
Id
IN_DATE
OUT_DATE
TOTAL_HOURS
1
2021-10-04 07:00:00
2021-10-04 08:00:00
1
Fiddle here.
To INSERT from a .csv file use the LOAD DATA INFILE command and add the TIMESTAMPDIFF calculation to the SET clause:
LOAD DATA INFILE 'c:/tmp/discounts_2.csv'
INTO TABLE Table_A
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS
(Id,#IN_DATE,#OUT_DATE)
SET IN_DATE=#IN_DATE,
OUT_DATE=#OUT_DATE,
TIMESTAMPDIFF(HOUR, #IN_DATE, #OUT_DATE);

filter timestamp column in SQL Oracle

I have a table with a Timestamp column which I need to filter after '2020-08-26', but every solution won't work
RUN_TIME
2020-07-22 04:22:07
2020-07-22 04:34:07
2020-07-22 04:45:07
2020-07-22 04:50:07
2020-07-22 04:55:08
I tried the below queries:
WHERE CAST (RUN_DATE AS DATE) >= TO_DATE('2020-08-26', 'yyyy-mm-dd')
WHERE to_date(RUN_DATE, 'YYYY-MM-DD hh24:mi:ss') >= to_date('26-08-2020 23:59:59', 'YYYY-MM-DD hh24:mi:ss')
WHERE RUN_DATE >= TO_TIMESTAMP('26-08-2020 23:59:59')
Use a TIMESTAMP literal:
SELECT *
FROM table_name
WHERE run_time >= TIMESTAMP '2020-08-27 00:00:00';
or, use a DATE literal:
SELECT *
FROM table_name
WHERE run_time >= DATE '2020-08-27';
or, use TO_TIMESTAMP with a format model:
SELECT *
FROM table_name
WHERE run_time >= TO_TIMESTAMP( '2020-08-27', 'YYYY-MM-DD' );
or, use TO_DATE with a format model:
SELECT *
FROM table_name
WHERE run_time >= TO_DATE( '2020-08-27', 'YYYY-MM-DD' );
Which for the sample data:
CREATE TABLE TABLE_NAME ( run_time TIMESTAMP(6) );
INSERT INTO table_name ( run_time )
SELECT TIMESTAMP '2020-07-22 04:22:07' FROM DUAL UNION ALL
SELECT TIMESTAMP '2020-07-22 04:34:07' FROM DUAL UNION ALL
SELECT TIMESTAMP '2020-07-22 04:45:07' FROM DUAL UNION ALL
SELECT TIMESTAMP '2020-07-22 04:50:07' FROM DUAL UNION ALL
SELECT TIMESTAMP '2020-07-22 04:55:08' FROM DUAL UNION ALL
SELECT TIMESTAMP '2020-08-26 23:59:59.999999' FROM DUAL UNION ALL
SELECT TIMESTAMP '2020-08-27 00:00:00' FROM DUAL;
All output:
| RUN_TIME |
| :------------------------ |
| 27-AUG-20 00.00.00.000000 |
db<>fiddle here
Just:
where run_date >= date '2020-08-26'
That's direct filtering against a date literal.
run_date is a timestamp already, so you should not attempt to convert it. Also, to_timestamp() takes a second argument, which specifies the format of the string; without it, it defaults to the nls_timestamp_format of your session (or database), which may not be what you expect

"IF EXISTS" in PostgreSQL - creating query that updates a record if exists and inserts into if not

I want to make a query "If a record within that second and this sensor_id exists, update it with provided new value, else create a record with that value, sensor_id and time".
I managed to create this query:
DO
$do$
BEGIN
IF EXISTS (
SELECT
1
FROM
public.measurement_pm2_5
WHERE
measurement_time >= TO_TIMESTAMP('06.07.2016 23:28:43', 'DD.MM.YYYY HH24:MI:SS')
AND measurement_time < TO_TIMESTAMP('06.07.2016 23:28:44', 'DD.MM.YYYY HH24:MI:SS')
AND sensor_id = 2
) THEN UPDATE
public.measurement_pm2_5
SET
measurement_value = 27
WHERE
measurement_time >= TO_TIMESTAMP('06.07.2016 23:28:43', 'DD.MM.YYYY HH24:MI:SS')
AND measurement_time < TO_TIMESTAMP('06.07.2016 23:28:44', 'DD.MM.YYYY HH24:MI:SS')
AND sensor_id = 2;
ELSE INSERT
INTO
public.measurement_pm2_5
( sensor_id, measurement_time, measurement_value )
VALUES
( 2, TO_TIMESTAMP('06.07.2016 23:28:43', 'DD.MM.YYYY HH24:MI:SS'), 27 );
END IF;
END;
$do$
LANGUAGE plpgsql;
But it doesn't work as expected.
Query OK, 0 rows affected (execution time: 62 ms; total time: 62 ms)
Although this query:
SELECT
1
FROM
public.measurement_pm2_5
WHERE
measurement_time >= TO_TIMESTAMP('06.07.2016 23:28:43', 'DD.MM.YYYY HH24:MI:SS')
AND measurement_time < TO_TIMESTAMP('06.07.2016 23:28:44', 'DD.MM.YYYY HH24:MI:SS')
AND sensor_id = 2
returns one record, the UPDATE part of the first query doesn't look to be executed.
I'm using PostgreSQL 9.5.
What am I doing wrong?
Edit:
measurement_pm2_5 table:
CREATE TABLE public.measurement_pm2_5 (
sensor_id SERIAL,
measurement_time TIMESTAMP WITHOUT TIME ZONE NOT NULL,
measurement_value NUMERIC(6,2) NOT NULL,
CONSTRAINT measurement_pm2_5_sensor_id_fkey FOREIGN KEY (sensor_id)
REFERENCES public.sensor(id)
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE
)
WITH (oids = false);
From your SQL code it is easy to tell that you are experienced in procedural programming languages. PL/pgSQL requires a different mindset though. Carefully read the docs on PL/pgSQL programming and start thinking in sets and operations that succeed or fail. This is not at all meant to belittle you; take it as well-intended advice from a fellow programmer who has seen both sides of the fence.
In this case, simply try the UPDATE and if it fails, do an INSERT instead.
DO $do$
DECLARE
obs timestamp := to_timestamp('06.07.2016 23:28:43', 'DD.MM.YYYY HH24:MI:SS');
BEGIN
UPDATE public.measurement_pm2_5
SET measurement_value = 27
WHERE measurement_time = date_trunc('second', obs)
AND sensor_id = 2;
IF NOT FOUND THEN
INSERT INTO public.measurement_pm2_5
(sensor_id, measurement_time, measurement_value)
VALUES (2, obs, 27);
END IF;
END;
$do$ LANGUAGE plpgsql;

Oracle: How to filter by date and time in a where clause

How can I do this:
select *
from tableName
where SESSION_START_DATE_TIME > To_Date ('12-Jan-2012 16:00', 'DD-MON-YYYY hh24:mi' )
SESSION_START_DATE_TIME is in the format '12/01/2012 13:16:32.000'
I tried where To_Date (SESSION_START_DATE_TIME, 'DD-MON-YYYY hh24:mi') > To_Date ('12-Jan-2012 16:00', 'DD-MON-YYYY hh24:mi' )
but no matter what I try I get the error:
SQL command not properly formed
In the example that you have provided there is nothing that would throw a SQL command not properly formed error. How are you executing this query? What are you not showing us?
This example script works fine:
create table tableName
(session_start_date_time DATE);
insert into tableName (session_start_date_time)
values (sysdate+1);
select * from tableName
where session_start_date_time > to_date('12-Jan-2012 16:00', 'DD-MON-YYYY hh24:mi');
As does this example:
create table tableName2
(session_start_date_time TIMESTAMP);
insert into tableName2 (session_start_date_time)
values (to_timestamp('01/12/2012 16:01:02.345678','mm/dd/yyyy hh24:mi:ss.ff'));
select * from tableName2
where session_start_date_time > to_date('12-Jan-2012 16:00', 'DD-MON-YYYY hh24:mi');
select * from tableName2
where session_start_date_time > to_timestamp('01/12/2012 14:01:02.345678','mm/dd/yyyy hh24:mi:ss.ff');
So there must be something else that is wrong.
If SESSION_START_DATE_TIME is of type TIMESTAMP you may want to try using the SQL function TO_TIMESTAMP. Here is an example:
SQL> CREATE TABLE t (ts TIMESTAMP);
Table created.
SQL> INSERT INTO t
2 VALUES (
3 TO_TIMESTAMP (
4 '1/12/2012 5:03:27.221008 PM'
5 ,'mm/dd/yyyy HH:MI:SS.FF AM'
6 )
7 );
1 row created.
SQL> SELECT *
2 FROM t
3 WHERE ts =
4 TO_TIMESTAMP (
5 '1/12/2012 5:03:27.221008 PM'
6 ,'mm/dd/yyyy HH:MI:SS.FF AM'
7 );
TS
-------------------------------------------------
12-JAN-12 05.03.27.221008 PM
Put it this way
where ("R"."TIME_STAMP">=TO_DATE ('03-02-2013 00:00:00', 'DD-MM-YYYY HH24:MI:SS')
AND "R"."TIME_STAMP"<=TO_DATE ('09-02-2013 23:59:59', 'DD-MM-YYYY HH24:MI:SS'))
Where
R is table name.
TIME_STAMP is FieldName in Table R.
Try:
To_Date (SESSION_START_DATE_TIME, 'MM/DD/YYYY hh24:mi') >
To_Date ('12-Jan-2012 16:00', 'DD-MON-YYYY hh24:mi' )
Obviously '12/01/2012 13:16:32.000' doesn't match 'DD-MON-YYYY hh24:mi' format.
Update:
You need 'MM/DD/YYYY hh24:mi:ss.ff' format and to use TO_TIMESTAMP instead of TO_DATE cause dates don't hold millis in oracle.