Netezza 内置 AGE 函数作为 Redshift 中的 UDF
Netezza In-Built AGE function as UDF in Redshift
我正在尝试将 Redshift 中的 Netezza AGE 函数作为 UDF 实现。我可以在 Python(Spyder IDE - Py 3.6)中得到正确的答案,但是当我在 Redshift 中作为 UDF 执行它时,它给了我不正确的输出。
我尝试在 Redshift 中以 select AGE_UDF('1994-04-04 20:10:52','2018-09-24 11:31:05');
执行。
这是RS UDF中使用的代码。
CREATE OR REPLACE FUNCTION AGE_UDF (START_DATE TIMESTAMP, END_DATE TIMESTAMP)
RETURNS varchar(100)
stable
AS $$
from datetime import datetime
from dateutil import relativedelta
START_DATE = datetime.strptime(START_DATE, '%Y-%m-%d %H:%M:%S')
END_DATE = datetime.strptime(END_DATE, '%Y-%m-%d %H:%M:%S')
difference = relativedelta.relativedelta(END_DATE, START_DATE)
years = difference.years
months = difference.months
days = difference.days
hours = difference.hours
minutes = difference.minutes
seconds = difference.seconds
age=''
if years == 0:
age=''
elif years == 1:
age+=str(years)+' year '
else:
age+=str(years)+' years '
if months == 0:
age+=''
elif months == 1:
age+=str(months)+' mon '
else:
age+=str(months)+' mons '
if days == 0:
age+=''
elif days == 1:
age+=str(days)+' day '
else:
age+=str(days)+' days '
age+=str(hours)+':'+str(minutes)+':'+str(seconds)
return age
$$ language plpythonu;
RS 输出:-8809.15:20:13
这是 Python (3.6) 中使用的代码。
from datetime import datetime
from dateutil import relativedelta
START_DATE = '1994-04-04 20:10:52'
START_DATE = datetime.strptime(START_DATE, '%Y-%m-%d %H:%M:%S')
END_DATE = '2018-09-24 11:31:05'
END_DATE = datetime.strptime(END_DATE, '%Y-%m-%d %H:%M:%S')
difference = relativedelta.relativedelta(END_DATE, START_DATE)
years = difference.years
months = difference.months
days = difference.days
hours = difference.hours
minutes = difference.minutes
seconds = difference.seconds
age=''
if years == 0:
age=''
elif years == 1:
age+=str(years)+' year '
else:
age+=str(years)+' years '
if months == 0:
age+=''
elif months == 1:
age+=str(months)+' mon '
else:
age+=str(months)+' mons '
if days == 0:
age+=''
elif days == 1:
age+=str(days)+' day '
else:
age+=str(days)+' days '
age+=str(hours)+':'+str(minutes)+':'+str(seconds)
print(age)
Python 的产出:24 年 5 周一 19 天 15:20:13
编辑:
我找到了实现 Netezza 功能的方法并将其粘贴在这里。
我仍然期待另一种有效的方式!!!干杯!!!
感谢支持和建议!!!
不需要 Python。这是封装逻辑的 SQL UDF。如果复数单位对你很重要,你将需要扩展它(mons
vs mon
)。
/*
Postgres AGE() Function
*/
CREATE OR REPLACE FUNCTION f_postgres_age(TIMESTAMP, TIMESTAMP)
RETURNS VARCHAR(64)
STABLE AS $$
-- Input: '1994-04-04 20:10:52', '2018-09-24 11:31:05'
-- Output: 24 years 5 mons 19 days 15:20:13
-- Input: '1994-10-04 20:10:52', '2019-06-12 11:31:05'
-- Output: 24 years 8 mons 7 days 15:20:13
-- Check: SELECT '1994-10-04 20:10:52'::TIMESTAMP
-- + INTERVAL '24 years' + INTERVAL '8 months' + INTERVAL '7 days'
-- + INTERVAL '15 hours' + INTERVAL '20 minutes' + INTERVAL '13 seconds';
-- Result: 2019-06-12 11:31:05
SELECT CASE WHEN DATEDIFF(year, DATE_TRUNC('year', )
, DATE_TRUNC('year', CASE WHEN DATEPART(month, ) > DATEPART(month, )
THEN - INTERVAL '1 Year' ELSE END)) > 0
THEN DATEDIFF(year, DATE_TRUNC('year', )
, DATE_TRUNC('year', CASE WHEN DATEPART(month, ) > DATEPART(month, )
THEN - INTERVAL '1 Year' ELSE END)) || ' years '
ELSE '' END
|| CASE WHEN ABS( DATEDIFF(month, DATE_TRUNC('month', ), DATE_TRUNC('month', ))
- DATEDIFF(month, DATE_TRUNC('year', )
, DATE_TRUNC('year', CASE WHEN DATEPART(month, ) > DATEPART(month, )
THEN - INTERVAL '1 Year' ELSE END))) > 0
THEN DATEDIFF(month, DATE_TRUNC('month', ), DATE_TRUNC('month', ))
- DATEDIFF(month, DATE_TRUNC('year', )
, DATE_TRUNC('year', CASE WHEN DATEPART(month, ) > DATEPART(month, )
THEN - INTERVAL '1 Year' ELSE END)) || ' mons '
ELSE '' END
|| CASE WHEN ABS( DATEDIFF(day, DATE_TRUNC('day', )+1, DATE_TRUNC('day', ))
- DATEDIFF(day, DATE_TRUNC('month', ), DATE_TRUNC('month', ))) > 0
THEN DATEDIFF(day, DATE_TRUNC('day', )+1, DATE_TRUNC('day', ))
- DATEDIFF(day, DATE_TRUNC('month', ), DATE_TRUNC('month', )) || ' days '
ELSE '' END
|| TO_CHAR((TIMESTAMP 'epoch'
+ ( DATEDIFF(second, , DATE_TRUNC('day', )+1 )
+ DATEDIFF(second, DATE_TRUNC('day', ), ) )
* INTERVAL '1 Second '),'HH24:MI:SS') age
$$ LANGUAGE SQL
;
我找到了与 Netezza 一样的输出方式!我们需要用不同的输入创建 4 个不同的 UDF!在这里,我为 (TIMESTAMP, TIMESTAMP)
添加了 UDF
create or replace function AGE_UDF_V2 (START_DATE TIMESTAMP, END_DATE TIMESTAMP)
returns VARCHAR
stable
as $$
# -*- coding: utf-8 -*-
"""
Created on Wed Sep 26 12:59:24 2018
@author: pnataraj
"""
from dateutil import relativedelta
from dateutil.parser import parse
if (START_DATE is None or END_DATE is None):
return None
else:
START_DATE = str(START_DATE).strip()
END_DATE = str(END_DATE).strip()
START_DATE = parse(START_DATE)
END_DATE = parse(END_DATE)
difference = relativedelta.relativedelta(START_DATE, END_DATE)
years = difference.years
months = difference.months
days = difference.days
hours = difference.hours
minutes = difference.minutes
seconds = difference.seconds
age=''
if years != 0:
if years == 1 or years == -1:
age+=str(years)+' year '
else:
age+=str(years)+' years '
if months != 0:
if months == 1 or months == -1:
age+=str(months)+' mon '
else:
age+=str(months)+' mons '
if days != 0:
if days == 1 or days == -1:
age+=str(days)+' day '
else:
age+=str(days)+' days '
if (hours !=0 or minutes !=0 or seconds != 0):
if (hours < 0 or minutes < 0 or seconds < 0):
age+=str("-"+format(abs(hours),"02")+":"+format(abs(minutes),"02")+":"+format(abs(seconds),"02"))
else:
age+=str(format(hours,"02")+":"+format(minutes,"02")+":"+format(seconds,"02"))
elif(hours == 0 and minutes ==0 and seconds == 0):
if len(age)>0:
age = age
else:
age = "00:00:00"
return age.strip()
$$ language plpythonu;
感谢所有的建议和帮助!希望它对那些正在做 Nz 到 AWS RS 迁移的人有帮助!
我正在尝试将 Redshift 中的 Netezza AGE 函数作为 UDF 实现。我可以在 Python(Spyder IDE - Py 3.6)中得到正确的答案,但是当我在 Redshift 中作为 UDF 执行它时,它给了我不正确的输出。
我尝试在 Redshift 中以 select AGE_UDF('1994-04-04 20:10:52','2018-09-24 11:31:05');
执行。
这是RS UDF中使用的代码。
CREATE OR REPLACE FUNCTION AGE_UDF (START_DATE TIMESTAMP, END_DATE TIMESTAMP)
RETURNS varchar(100)
stable
AS $$
from datetime import datetime
from dateutil import relativedelta
START_DATE = datetime.strptime(START_DATE, '%Y-%m-%d %H:%M:%S')
END_DATE = datetime.strptime(END_DATE, '%Y-%m-%d %H:%M:%S')
difference = relativedelta.relativedelta(END_DATE, START_DATE)
years = difference.years
months = difference.months
days = difference.days
hours = difference.hours
minutes = difference.minutes
seconds = difference.seconds
age=''
if years == 0:
age=''
elif years == 1:
age+=str(years)+' year '
else:
age+=str(years)+' years '
if months == 0:
age+=''
elif months == 1:
age+=str(months)+' mon '
else:
age+=str(months)+' mons '
if days == 0:
age+=''
elif days == 1:
age+=str(days)+' day '
else:
age+=str(days)+' days '
age+=str(hours)+':'+str(minutes)+':'+str(seconds)
return age
$$ language plpythonu;
RS 输出:-8809.15:20:13
这是 Python (3.6) 中使用的代码。
from datetime import datetime
from dateutil import relativedelta
START_DATE = '1994-04-04 20:10:52'
START_DATE = datetime.strptime(START_DATE, '%Y-%m-%d %H:%M:%S')
END_DATE = '2018-09-24 11:31:05'
END_DATE = datetime.strptime(END_DATE, '%Y-%m-%d %H:%M:%S')
difference = relativedelta.relativedelta(END_DATE, START_DATE)
years = difference.years
months = difference.months
days = difference.days
hours = difference.hours
minutes = difference.minutes
seconds = difference.seconds
age=''
if years == 0:
age=''
elif years == 1:
age+=str(years)+' year '
else:
age+=str(years)+' years '
if months == 0:
age+=''
elif months == 1:
age+=str(months)+' mon '
else:
age+=str(months)+' mons '
if days == 0:
age+=''
elif days == 1:
age+=str(days)+' day '
else:
age+=str(days)+' days '
age+=str(hours)+':'+str(minutes)+':'+str(seconds)
print(age)
Python 的产出:24 年 5 周一 19 天 15:20:13
编辑:
我找到了实现 Netezza 功能的方法并将其粘贴在这里。 我仍然期待另一种有效的方式!!!干杯!!!
感谢支持和建议!!!
不需要 Python。这是封装逻辑的 SQL UDF。如果复数单位对你很重要,你将需要扩展它(mons
vs mon
)。
/*
Postgres AGE() Function
*/
CREATE OR REPLACE FUNCTION f_postgres_age(TIMESTAMP, TIMESTAMP)
RETURNS VARCHAR(64)
STABLE AS $$
-- Input: '1994-04-04 20:10:52', '2018-09-24 11:31:05'
-- Output: 24 years 5 mons 19 days 15:20:13
-- Input: '1994-10-04 20:10:52', '2019-06-12 11:31:05'
-- Output: 24 years 8 mons 7 days 15:20:13
-- Check: SELECT '1994-10-04 20:10:52'::TIMESTAMP
-- + INTERVAL '24 years' + INTERVAL '8 months' + INTERVAL '7 days'
-- + INTERVAL '15 hours' + INTERVAL '20 minutes' + INTERVAL '13 seconds';
-- Result: 2019-06-12 11:31:05
SELECT CASE WHEN DATEDIFF(year, DATE_TRUNC('year', )
, DATE_TRUNC('year', CASE WHEN DATEPART(month, ) > DATEPART(month, )
THEN - INTERVAL '1 Year' ELSE END)) > 0
THEN DATEDIFF(year, DATE_TRUNC('year', )
, DATE_TRUNC('year', CASE WHEN DATEPART(month, ) > DATEPART(month, )
THEN - INTERVAL '1 Year' ELSE END)) || ' years '
ELSE '' END
|| CASE WHEN ABS( DATEDIFF(month, DATE_TRUNC('month', ), DATE_TRUNC('month', ))
- DATEDIFF(month, DATE_TRUNC('year', )
, DATE_TRUNC('year', CASE WHEN DATEPART(month, ) > DATEPART(month, )
THEN - INTERVAL '1 Year' ELSE END))) > 0
THEN DATEDIFF(month, DATE_TRUNC('month', ), DATE_TRUNC('month', ))
- DATEDIFF(month, DATE_TRUNC('year', )
, DATE_TRUNC('year', CASE WHEN DATEPART(month, ) > DATEPART(month, )
THEN - INTERVAL '1 Year' ELSE END)) || ' mons '
ELSE '' END
|| CASE WHEN ABS( DATEDIFF(day, DATE_TRUNC('day', )+1, DATE_TRUNC('day', ))
- DATEDIFF(day, DATE_TRUNC('month', ), DATE_TRUNC('month', ))) > 0
THEN DATEDIFF(day, DATE_TRUNC('day', )+1, DATE_TRUNC('day', ))
- DATEDIFF(day, DATE_TRUNC('month', ), DATE_TRUNC('month', )) || ' days '
ELSE '' END
|| TO_CHAR((TIMESTAMP 'epoch'
+ ( DATEDIFF(second, , DATE_TRUNC('day', )+1 )
+ DATEDIFF(second, DATE_TRUNC('day', ), ) )
* INTERVAL '1 Second '),'HH24:MI:SS') age
$$ LANGUAGE SQL
;
我找到了与 Netezza 一样的输出方式!我们需要用不同的输入创建 4 个不同的 UDF!在这里,我为 (TIMESTAMP, TIMESTAMP)
添加了 UDFcreate or replace function AGE_UDF_V2 (START_DATE TIMESTAMP, END_DATE TIMESTAMP)
returns VARCHAR
stable
as $$
# -*- coding: utf-8 -*-
"""
Created on Wed Sep 26 12:59:24 2018
@author: pnataraj
"""
from dateutil import relativedelta
from dateutil.parser import parse
if (START_DATE is None or END_DATE is None):
return None
else:
START_DATE = str(START_DATE).strip()
END_DATE = str(END_DATE).strip()
START_DATE = parse(START_DATE)
END_DATE = parse(END_DATE)
difference = relativedelta.relativedelta(START_DATE, END_DATE)
years = difference.years
months = difference.months
days = difference.days
hours = difference.hours
minutes = difference.minutes
seconds = difference.seconds
age=''
if years != 0:
if years == 1 or years == -1:
age+=str(years)+' year '
else:
age+=str(years)+' years '
if months != 0:
if months == 1 or months == -1:
age+=str(months)+' mon '
else:
age+=str(months)+' mons '
if days != 0:
if days == 1 or days == -1:
age+=str(days)+' day '
else:
age+=str(days)+' days '
if (hours !=0 or minutes !=0 or seconds != 0):
if (hours < 0 or minutes < 0 or seconds < 0):
age+=str("-"+format(abs(hours),"02")+":"+format(abs(minutes),"02")+":"+format(abs(seconds),"02"))
else:
age+=str(format(hours,"02")+":"+format(minutes,"02")+":"+format(seconds,"02"))
elif(hours == 0 and minutes ==0 and seconds == 0):
if len(age)>0:
age = age
else:
age = "00:00:00"
return age.strip()
$$ language plpythonu;
感谢所有的建议和帮助!希望它对那些正在做 Nz 到 AWS RS 迁移的人有帮助!