Data value "0" has invalid format error in redshift - sql

We are facing a weird problem with one of our query.
Below is the query we are running
INSERT into test
SELECT
member.name as mem_name,
CASE WHEN ( member.dob>0 AND length (member.dob)=8 ) THEN (DATEDIFF(year,to_date("dob",'YYYYMMDD'), to_date(20140716,'YYYYMMDD'))) WHEN ( member.dob=0 ) Then 0 END As Age,
20140716021501
FROM
member
Below is the sample data present in our table.
|name |dob
|Ajitsh |0 |
|rk |51015 |
|s_thiagarajan |19500130 |
|madhav_7 |19700725 |
|1922 |0 |
|rekha |25478 |
|vmkurup |0 |
|ravikris |19620109 |
|ksairaman |0 |
|sruthi |0 |
|rrbha |19630825 |
|sunilsw |0 |
|sunilh |0 |
|venky_pmv |19701207 |
|malagi |0 |
|an752001 |0 |
|edsdf |19790201 |
|anuanand |19730724 |
|fresh |19720821 |
|ampharcopharma |19590127 |
|Nanze |19621123 |
The date of birth is stored in bigint as YYYYMMDD format.
In the data there are some rows, in which date is invalid like 0, 51015.
On some instances this query raises the following error.
INSERT INTO test not successful
An error occurred when executing the SQL command:
INSERT into test
SELECT
member.name as mem_name,
CASE WHEN ( member.dob>0 AND length (member.dob)=8 ) THEN (DATEDIFF(y...
ERROR: Data value "0" has invalid format
Detail:
-----------------------------------------------
error: Data value "0" has invalid format
code: 1009
context: PG ERROR
query: 92776
location: pg_utils.cpp:2731
process: query1_30 [pid=1434]
-----------------------------------------------
Execution time: 3.99s
1 statement failed.
But the strange thing is, it raises the error randomly and not all the time.
Many times it works without any change in query or dataset.
Sometime it also works in second or third attempt.
My doubt is that to_date function is giving this error. But why randomly
and not gives error on every run.
To support my assumption I also tried this small query.
SELECT to_date(20140716,'YYYYMMDD'), to_date(0,'YYYYMMDD');
But this also creates the same scenario. It raises error randomly, while
runs smoothly rest of the times.

If is it fine to ignore this type of values and just convert this to Date format you can follow the below way.
SELECT to_date('20140716','YYYYMMDD'), to_date('0','FMYYYYMMDD');
Here FM suppresses leading zeroes and trailing blanks that would otherwise be added to make the output of a pattern be fixed-width.

Related

ACCESS: calculate timestamp difference between rows

Here is the data I am working with in MS Access from a system tracking when a agent makes system changes:
|agentid|eventtype|reasoncode|eventdatetimelocal |
|1830 |2 |32762 |01/01/2014 7:11:44 PM|
|1830 |3 |0 |01/01/2014 7:13:46 PM|
|1830 |2 |32762 |01/01/2014 7:14:55 PM|
|1833 |2 |0 |01/01/2014 7:11:35 PM|
|1833 |3 |32762 |01/01/2014 7:13:25 PM|
I need to determine the number of seconds which elapsed between rows by agent. I would also like to preserve the detail of the eventtype and reasoncode.
I tried joining on a subqry but it's not working:
SELECT sub1.agentid,
sub1.eventtype,
sub1.reasoncode,
sub1.eventdatetimelocal,
(sub1.next_timestamp-sub1.eventdatetimelocal) AS duration
FROM (SELECT i.agentid,
eventdatetimelocal,
eventtype,
reasoncode, (SELECT
Min([eventdatetimelocal])
FROM state_detail_tbl
WHERE [eventdatetimelocal] > i.eventdatetimelocal
) AS next_timestamp
FROM state_detail_tbl AS i
WHERE i.eventdatetimelocal BETWEEN #01/01/2014# AND #01/31/2014#
) AS sub1;
You can try this query
SELECT sub1.agentid,
sub1.eventtype,
sub1.reasoncode,
sub1.eventdatetimelocal,
(SELECT TOP 1 sub2.eventdatetimelocal - sub1.eventdatetimelocal
FROM state_detail_tbl AS sub2
WHERE sub1.agentid=sub2.agentid
AND sub2.eventdatetimelocal > sub1.eventdatetimelocal
ORDER BY sub2.eventdatetimelocal) AS duration
FROM state_detail_tbl sub1
WHERE (SELECT TOP 1 eventdatetimelocal
FROM state_detail_tbl AS s3
WHERE sub1.agentid=s3.agentid
AND s3.eventdatetimelocal > sub1.eventdatetimelocal) Is Not Null
AND sub1.eventdatetimelocal BETWEEN #01/01/2014# AND #01/31/2014#
ORDER BY sub1.agentid, sub1.eventdatetimelocal;
I received an error from the query below stating something along the lines of "this query can only return a maximum of one row". But the query along with this reference: Calculating time difference between activity timestamps in a query gave me what I needed which I am listing below for reference. I decided that my initial needs were too broad and so I simplified the query to return the bare minimum data needed to bring the timestamp up to the previous row. I can step another query in with datediff to figure out the seconds. It takes awhile for this to process but it works and can run overnight if required.
SELECT i.agentid, i.eventtype, i.reasoncode, eventdatetimelocal, (SELECT
Min([eventdatetimelocal]) FROM state_detail_subqry WHERE agentid = i.agentid
AND [eventdatetimelocal]>i.[eventdatetimelocal]) AS next_timestamp
FROM state_detail_subqry AS i
ORDER BY agentid, eventdatetimelocal;

Delphi 7 - error when get values using sql operator in

Got no answer on related thread, so i make this question. I've been searched for how to retrieve records value using where clause with multiple values and i got this.
table example :
|ID |PRICE|
|1 |3000 |
|2 |2000 |
|3 |1000 |
|4 |5000 |
|5 |4000 |
SQL query :
DM.Zread.Close;
DM.Zread.SQL.CommaText := 'select PRICE from DVD where ID in (1, 2, 3)';
DM.Zread.Open;
Above gave me an error, when i only put one 1 values which is (1) or (2) it's works fine.
Questions are :
how to straight it, so i could get the values from 3 different
records ?
how to apply it on string values instead ?
SQL is a TStrings subclass. When you set CommaText using the above, you are actually setting your query to:
select PRICE from DVD where ID in (1
2
3)
This obviously won't work.
You want to set the Text property or use Add() method to add separate lines.
Try using CommandText rather than CommaText on your SQL call
DM.Zread.Close;
DM.Zread.SQL.CommaText := 'select PRICE from DVD where ID in (1, 2, 3)';
DM.Zread.Open;
DM.Zread.SQL.CommandText := 'select PRICE from DVD where ID in (1, 2, 3)';

My PostgreSQL calculations don't include decimals

I don't dabble in SQL queries much and rely on google when I need something more than the basics, and have come up with a problem.
I am trying to calculate a value and it returns a result rounded down to the nearest integer.
To test this out, I wrote the following query:
select ELAPTIME AS "ELAPSEC", ELAPTIME/60 AS "ELAPMIN" from CMR_RUNINF
The result is:
+-----------+-----------+
|ELAPSEC |ELAPMIN |
+-----------+-----------+
|258 |4 |
+-----------+-----------+
|0 |0 |
+-----------+-----------+
|2128 |35 |
+-----------+-----------+
|59 |0 |
+-----------+-----------+
I'm trying to do a bit more than this, but I've simplified it to make it easier to explain the problem. How do I ensure that this calculation returns the decimal point?
postgres=# SELECT 258/60::float;
?column?
----------
4.3
(1 row)
Your SQL product performs integral division because both operands are integers. ELAPTIME's integer type is determined be the table structure and 60 is automatically assumed to be integer because it has no decimal point.
There are two methods of resolving the issue:
Convert either operand to a non-integer numeric type explicitly:
CAST(ELAPTIME AS float) / 60
Write 60.0 instead of 60 so that the parser can see you are not dividing an integer by an integer:
ELAPTIME / 60.0
Simply try this
SELECT ELAPTIME AS "ELAPSEC", ELAPTIME/60 :: Float AS "ELAPMIN"
FROM CMR_RUNINF
Or:
SELECT ELAPTIME AS "ELAPSEC", ELAPTIME/60 :: Real AS "ELAPMIN"
FROM CMR_RUNINF
Fiddle Demo

QSqlField real type name

i'm looking for a way to retrieve real database type name from qtsql model.
Unfortunately
QVariant::typeToName(field.type())
Where field is QSqlField type
gives me already mapped type to some Qt type. Is it possible to get real names using Qt?
i found a way to retrieve the real database type with following query:
QSqlQuery query("PRAGMA table_info(tableName)");
As a result you will get:
cid|name |type |notnull |dflt_value |pk
0 |id |integer |0 | |1
1 |name |varchar(45) |1 | |0
thanks to this post:
Getting the type of a column in SQLite
Hope this helps

adding and incrementing date and time (Postgresql)

The below is a table that is meant to show when a media will play. so basically it has a start time (starts), the length of the track (clip_length), and when it ends (ends = starts + clip_length), and finally the position of the track.
|starts | ends |position |file_id| clip_length
|2013-08-30 22:00:00 | 2013-08-30 22:03:08 |0 |16 |00:03:08.081768
|2013-08-30 22:03:08 | 2013-08-30 22:06:33 |1 |17 |00:03:25.436485
|2013-08-30 22:06:33 | 2013-08-30 22:09:07 |2 |7 |00:02:33.79968
|2013-08-30 22:09:07 | 2013-08-30 22:12:21 |3 |3 |00:03:14.020273
|2013-08-30 22:12:21 | 2013-08-30 22:15:31 |4 |8 |00:03:10.466689
what i want to do is to add a record, at say position =2 , shown bellow. I have been able to increment the positions, how ever the problem lies with the fact that the times are all messed up.
|starts | ends |position |file_id|clip_length
|2013-08-30 22:00:00 | 2013-08-30 22:03:08 |0 |16 |00:03:08.081768
|2013-08-30 22:03:08 | 2013-08-30 22:06:33 |1 |17 |00:03:25.436485
|2013-08-30 22:06:33 | 2013-08-30 22:09:07 |2 |7 |00:02:33.79968
|2013-08-30 22:06:33 | 2013-08-30 22:11:03 |3 |1 |00:04:30.006958
|2013-08-30 22:09:07 | 2013-08-30 22:12:21 |4 |3 |00:03:14.020273
|2013-08-30 22:12:21 | 2013-08-30 22:15:31 |5 |8 |00:03:10.466689
so it possible to use the first start time.. as point 00, and add clip_length to starts and save in ends, for the first one. then for the second one use the first ends value as the starts and do this recursively till the end (following the positions) .
thanks in advance..
SQL Fiddle
update clip c
set
starts = s.starts,
ends = s.ends
from (
select
starts,
starts + clip_length as ends,
file_id,
position
from (
select
'2013-08-30 22:00:00'::timestamp
+ sum(clip_length) over(order by position)
- clip_length as starts,
clip_length,
file_id,
position
from clip
) s
) s
where c.file_id = s.file_id
Your data model is pretty borked. You're storing at least two pieces of redundant information. You need starts and file_id and any one of clip_length, ends or position; they can each be calculated from each other.
Right now you are storing redundant data, which creates the problem you now have where the data is not internally consistent, it has conflicts within its self.
In this case it sounds like position is trusted and the others aren't. Here's what I'd do:
SELECT
(SELECT min(starts) FROM Sometable)
+ COALESCE(
sum(clip_length) OVER all_rows_but_last,
INTERVAL '0' second
)
AS starts,
(SELECT min(starts) FROM Sometable)
+ COALESCE(
sum(clip_length) OVER all_rows_but_last,
INTERVAL '0' second
) + clip_length
AS ends,
position,
clip_length
FROM Sometable
WINDOW all_rows_but_last AS (ORDER BY position ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING);
see: http://sqlfiddle.com/#!12/ca5fa/1
The principle here is to find the lowest start - the one known to be valid - and ignore the following ends and starts as redundant and useless. Instead, add the running total of the previous durations as the start, and the same running total plus the current interval as the end.
You'll notice that this isn't an update. That's because I think you should actually:
change position to a floating point value or large integer so you don't need to re-number when you insert an entry. If you put something between 1 and 2 give it position 0.5. Or start with 10000, 20000 etc so you can insert 15000.
Get rid of the ends column completely. calculate it from starts + clip_length
Move starts to a separate table where it's stored only once, for the series of segments. Calculate clip start times on the fly from the sum of the lengths of previous clips since the start.
Re-define the current table as a view over the two tables described above.
That's making a lot of guesses about your data and how you're using it, but you haven't said much about what you're doing.
with cte as (
select
'2013-08-30 22:00:00'::timestamp
+ sum(clip_length) over(order by position) as ends,
file_id
from clip
)
update clip as cl set
starts = c.ends - cl.clip_length,
ends = c.ends
from cte as c
where cl.file_id = c.file_id;
=>sql fiddle
Actually, you could live without start and end time in your table at all. You can remove this columns from your table and create function like this:
create or replace function clip_layout(_starts timestamp)
returns table(
starts timestamp, ends timestamp,
"position" int, file_id int,clip_length interval
)
as
$$
with cte as (
select
_starts + sum(clip_length) over(order by position) as ends,
file_id, clip_length, position
from clip
)
select
ends - clip_length as starts,
ends, position,
file_id, clip_length
from cte
$$
language sql;
So you can see start/end times starting from anytime:
select * from clip_layout('2013-08-30 22:00:00'::timestamp)
=>sql fiddle demo