Oracle no result from comparing to date - sql

I have run this simple query and return no result
enterselect * from record where recorddate = TO_DATE(2018, 'YYYY');
I have tested
Select to_date(recorddate,'YYYY') from record
It return ora01830:date format picture ends before converting entire input string
Here is my table structure :
create table record(
recordid varchar2(10),
singerid varchar2(10),
producedcountryid varchar2(10),
songid varchar2(10),
recorddate date,
constraint recordid_pk primary key (recordid),
constraint singerid2_fk foreign key (singerid) references singer(singerid),
constraint songid2_fk foreign key (songid) references song(songid)
);

DATEs in Oracle include hours, minutes and seconds.
So unless there are any RECORDDATEs that are at exactly 00:00:00 in the given month, the predicate where recorddate = TO_DATE(2018, 'YYYY') will not find anything to match.
In the second query, to_date(recorddate,'YYYY') is not a valid syntax for using to_date. Please see to_date for more information.
If you are trying to find all the RECORDs with RECORDDATEs in the year 2018, There are many ways to do so. Below are a couple examples.
CREATE TABLE RECORD (LOREM_IPSUM NUMBER, RECORDDATE DATE);
INSERT INTO RECORD VALUES (1,DATE '2017-05-05');
INSERT INTO RECORD VALUES (2,DATE '2018-05-05');
COMMIT;
SELECT * FROM RECORD;
LOREM_IPSUM RECORDDATE
1 05-MAY-17
2 05-MAY-18
Then:
SELECT * FROM RECORD WHERE EXTRACT(YEAR FROM RECORDDATE) = 2018;
Result:
LOREM_IPSUM RECORDDATE
2 05-MAY-18
-- Or:
SELECT * FROM RECORD WHERE TO_CHAR(RECORDDATE,'YYYY') = '2018';
Result:
LOREM_IPSUM RECORDDATE
2 05-MAY-18
If you want records from a specific year + month, you can:
SELECT * FROM RECORD WHERE TRUNC(RECORDDATE,'MM') = DATE '2017-05-01';
Result:
LOREM_IPSUM RECORDDATE
1 05-MAY-17

You will get the result set you want by querying the year-part of the date column recorddate.
select * from record
where extract (year from recorddate) = 2018

Related

Add date to SQL table

Presto SQL
The idea is to get the historic data from the table by querying date. How to add current_date (YYYY-MM-DD) data I will set a refresh on daily. So when I want to look back of 5 days data I get the info.
**Data type **
member_id bigint
segemnt_id integer
DROP TABLE IF EXISTS ABC;
CREATE TABLE ABC AS ( SELECT member_id, Segment_id FROM XYZ)
This XYZ table has information of member_id and segment_id (Creating a separate table since XYZ contains many column just to reduce the load)
CREATE TABLE QQQ
(member_id bigint,
segment_id int)
INSERT INTO QQQ
(SELECT*, current_date as date, member_id, segment_id FROM ABC);

SQL statement to get $0 if the customer has no billing from any specific year

I am trying to find the average billing amount per year from 2019 to 2021 for every customer, and I want to return $0 if the customer has no billing from any specific year. I tried doing a left join but unfortunately it does not give the result I need. In the table below, how do I return $0 for customer_id 1 since the year for 2021 does not exist. Thanks.
billing table:
customer_id
billing_id
created_date
billing_amount
1
id_11
2019-06-21
100
1
id_12
2020-05-11
126
1
id_13
2019-12-28
86
2
id_21
2019-12-28
28
2
id_22
2020-12-28
56
2
id_23
2021-12-28
26
Here is my incorrect query:
Select a.customer_id,
extract(year from a.created_date),
avg(a.billing_amount)
from billing as a
left join billing as b
on a.customer_id = b.customer_id
where a.created_date between '2019-01-01' and '2021-12-31'
group by 1, 2
It was edit for add the links
You can try using WITH
First the DDL statements
create database test;
create table billing (
billing_id int,
customer_id int,
created_date date,
billing_amount int
);
alter table billing add constraint pk_billing primary key (billing_id);
create table customer (
customer_id int,
name varchar
)
alter table customer add constraint pk_customer primary key (customer_id);
alter table billing add constraint fk_customer foreign key (customer_id) references customer (customer_id);
Now the DML statements
insert into customer values (1,'Client 1'), (2,'Client 2');
insert into billing values (11,1,'2019-06-21',100),(12,1,'2020-05-11',126),(13,1,'2019-12-28',86),(21,2,'2019-12-28',28),(22,2,'2020-12-28',56),(23,2,'2021-12-28',26);
And finally the DQL query with WITH
with customer_year as (select distinct a.customer_id,vy."Year"
from billing a,(select distinct extract(year from a.created_date) as "Year"
from billing as a
where a.created_date between '2019-01-01' and '2021-12-31') vy
order by customer_id,vy."Year")
select cy.customer_id,cy."Year",
(select case when avg(a.billing_amount) is null then 0 else avg(a.billing_amount) end
from billing a
where a.customer_id = cy.customer_id and
extract(year from a.created_date) = cy."Year")
from customer_year cy;
This answer is for PostgreSQL
For MySQL or MariaDB change something in the DDL and the DQL
You can check in:
PostgreSQL
MySQL
MariaDB

How can I add the current date in ORACLE SQL column?

How can I add the "now" date in a column? I want to achieve the following scenario: if I insert a row today the date column will have the value 25/10/2021 and if tomorrow I'll execute a SELECT statement, I want to see that column updated with the value 26/10/2021 and so on. Is there a way to keep the column updated without me doing anything manually? Thanks.
Later edit: I want to use that column for a PERIOD in a temporal table. Example: PERIOD FOR example_period(some_date, now_date)
In your request comments you have altered your request fundamentally.
One problem: You have an open date range, with a beginning date and an ending date. But when displaying this, you want to substitute the no end" with the current date. This is usually done by storing null (no value) for the date. In a query you can then use COALESCE to replace that with the current date:
SELECT
empno,
salary,
start_date AS first_day,
COALESCE(end_date, TRUNC(SYSDATE)) AS last_day
FROM salaries;
And for convenience you can make this a view:
CREATE VIEW v_salaries AS SELECT <above query>
Another problem is that you want this null to change when a newer salary information gets added.
Manually you would just
INSERT INTO salaries (empno, salary, start_date, end_date)
VALUES(50, 1200, TRUNC(SYDATE), NULL);
UPDATE salaries SET end_date = TRUNC(SYSDATE) - 1
WHERE empno = 50 AND end_date IS NULL;
If you want this update to happen automatically, there are mainly two options:
write a procedure for a new salary that does the insert and update
write a trigger to perform the update
That doesn't make any sense. It is as if you'd just
select empno, ename,
sysdate --> this
from employees
every time.
SELECT won't update any column value, so ... why would you store such a date in the first place, if you want to keep it synchronized with sysdate?
But, if you want Oracle to insert sysdate into that column as its default value, you'd then create column as such, e.g.
SQL> create table test
2 (id number,
3 datum date default sysdate
4 );
Table created.
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> insert into test (id) values (1);
1 row created.
SQL> select * from test;
ID DATUM
---------- -------------------
1 25.10.2021 14:05:02
SQL>
But, it would remain the same "forever", unless you actually update its value.
Add a trigger that fill a column with sysdate :
create or replace TRIGGER TRG_FILL_DATE
BEFORE INSERT ON MY_TABLE
FOR EACH ROW
WHEN (NEW.MY_DATE_COLUMN IS NULL)
BEGIN
SELECT sysdate INTO :NEW.MY_DATE_COLUMN FROM DUAL;
END;
Or as suggested use 'DEFAULT sysdate' on your column.
You can use a generated column:
CREATE TABLE salaries (
id NUMBER(10,0)
GENERATED ALWAYS AS IDENTITY
CONSTRAINT salaries__id__pk PRIMARY KEY,
emp_id CONSTRAINT salaries__emp_id__fk REFERENCES employees (id)
NOT NULL,
salary NUMBER(12,2)
NOT NULL,
start_date DATE
NOT NULL,
end_date DATE
NULL,
assumed_end_date DATE
GENERATED ALWAYS AS (date_or_now(end_date))
NOT NULL
);
and create the DETERMINISTIC function (in a slight abuse of how it is supposed to be used):
CREATE FUNCTION date_or_now (dt IN DATE) RETURN DATE DETERMINISTIC
IS
BEGIN
RETURN COALESCE(dt, SYSDATE);
END;
/
Then if you:
INSERT INTO salaries (emp_id, salary, start_date)
VALUES (1, 123, DATE '2021-01-01');
Then:
SELECT *
FROM salaries;
The output is:
ID
EMP_ID
SALARY
START_DATE
END_DATE
ASSUMED_END_DATE
1
1
123
2021-01-01 00:00:00
2021-10-25 13:28:08
Then if you do:
UPDATE salaries
SET END_DATE = DATE '2021-10-01'
WHERE id = 1;
INSERT INTO salaries (emp_id, salary, start_date)
VALUES (1, 234, DATE '2021-10-01');
Then:
SELECT *
FROM salaries;
The output is:
ID
EMP_ID
SALARY
START_DATE
END_DATE
ASSUMED_END_DATE
1
1
123
2021-01-01 00:00:00
2021-10-01 00:00:00
2021-10-01 00:00:00
2
1
234
2021-10-01 00:00:00
2021-10-25 13:28:08
db<>fiddle here

number of days gap in between 2 dates to include the resultant data as another column

In sql server how can we get days gap in between 2 dates (I am fetching these 2 dates from other two columns as Sdate and EDate). I want to include the resultant data as another column
CREATE TABLE Remaingdays1
(
id INT NOT NULL PRIMARY KEY,
SDate DATE,
EDate Date,
remaingdays as SDate-EDate-- This should be the resultant of days
);
you can use computed column:
CREATE TABLE Remaingdays1 ( id INT NOT NULL PRIMARY KEY,
SDate DATE, EDate Date,
remaingdays as (datediff(day, sdate,edate)))

Informix - Create table with function weekday

I'm trying to create a table on Informix (11.70). I want to add the function WEEKDAY to a datetime value on the CREATE clause, so that I can automatically get an integer returned when inserting data.
For example.
CREATE TABLE orders (
order_num serial
order_date datetime year to second
order_weekday datetime year to second
)
I've tried the following and I get syntax error.
CREATE TABLE orders (
order_num serial
order_date datetime year to second
order_weekday WEEKDAY(datetime) year to second
)
Also this
CREATE TABLE orders (
order_num serial
order_date datetime year to second
WEEKDAY(order_weekday) datetime year to second
)
Is there some way to achieve this?
What are you trying to achieve? It is a fundamental principle of RDBMS normalisation that you should not store a value that can be derived from another existing field. You can calculate WEEKDAY(order_date) any time you need it at virtually no cost.
However, if you really want to do this, what you need to do is write an INSERT TRIGGER, as #JonathanLeffer suggested whilst I was writing this.
You might also want to clarify what you mean by "get an integer returned". The database returns something on a successful INSERT, but you cannot override that arbitrarily. If you really want to do that, you need to write a PROCEDURE to handle inserting the record to the orders table and returning the value you require.
You best bet is probably using FOR EACH ROW triggers which assign to the weekday column on INSERT and UPDATE given the value in the Order-Date column.
As RET notes in his answer, it is often best not to store derived data, especially not such readily derivable data as the weekday.
However, assuming you need to do so, then your trigger would look like:
BEGIN WORK;
CREATE TABLE orders
(
order_num SERIAL NOT NULL,
order_date DATETIME YEAR TO SECOND NOT NULL,
order_weekday INTEGER CHECK (order_weekday BETWEEN 0 AND 6) NOT NULL
);
INSERT INTO orders VALUES(0, CURRENT YEAR TO SECOND, WEEKDAY(MOD(WEEKDAY(TODAY) + 3, 7)));
SELECT *, WEEKDAY(order_date) AS calc_weekday FROM orders;
order_num order_date order_weekday calc_weekday
SERIAL DATETIME YEAR TO SECOND INTEGER SMALLINT
1 2016-02-04 23:21:36 0 4
CREATE TRIGGER i_orders INSERT ON orders
REFERENCING NEW AS NEW
FOR EACH ROW
(
UPDATE orders
SET order_weekday = WEEKDAY(NEW.order_date)
WHERE order_num = NEW.order_num
);
CREATE TRIGGER u_orders UPDATE OF order_date ON orders
REFERENCING NEW AS NEW
FOR EACH ROW
(
UPDATE orders
SET order_weekday = WEEKDAY(NEW.order_date)
WHERE order_num = NEW.order_num
);
INSERT INTO orders(order_num, order_date) VALUES(0, CURRENT YEAR TO SECOND);
SELECT *, WEEKDAY(order_date) AS calc_weekday FROM orders;
order_num order_date order_weekday calc_weekday
SERIAL DATETIME YEAR TO SECOND INTEGER SMALLINT
1 2016-02-04 23:21:36 0 4
2 2016-02-04 23:21:36 4 4
UPDATE orders
SET order_date = order_date - 10 UNITS DAY
WHERE order_weekday != WEEKDAY(order_date);
SELECT *, WEEKDAY(order_date) AS calc_weekday FROM orders;
order_num order_date order_weekday calc_weekday
SERIAL DATETIME YEAR TO SECOND INTEGER SMALLINT
1 2016-01-25 23:21:36 1 1
2 2016-02-04 23:21:36 4 4
ROLLBACK WORK;