Sql 如何添加多列值?
我必须询问那些在2010年1月至2012年12月期间行驶超过43万英里的司机。 我正为此努力Sql 如何添加多列值?,sql,oracle,Sql,Oracle,我必须询问那些在2010年1月至2012年12月期间行驶超过43万英里的司机。 我正为此努力 SELECT t.DRIVERID FROM BBI_BC.TRUCKS t WHERE t.JAN_2010_MILES + t. FEB_2010_MILES + .....+ t.DEC_2012_MILES > 43000; 所以问题是,如何避免在WHERE子句中键入所有这些列。答案是你不能。该表的设计者选择忽略已确立的数据库规范化行业标准规则。他们这样做的原因无关紧要:结果是每个查询
SELECT t.DRIVERID
FROM BBI_BC.TRUCKS t
WHERE t.JAN_2010_MILES + t. FEB_2010_MILES + .....+ t.DEC_2012_MILES > 43000;
所以问题是,如何避免在WHERE子句中键入所有这些列。答案是你不能。该表的设计者选择忽略已确立的数据库规范化行业标准规则。他们这样做的原因无关紧要:结果是每个查询表的人都必须编写冗长且难以维护的查询 可以选择动态查询生成:运行此查询,然后剪切“n”并将输出粘贴到WHERE子句中:
select ' + t.' || column_name
from all_tab_columns
where owner = 'BBI_BC'
and table_name = 'TRUCKS'
and (column_name like '%2010_MILES'
or column_name like '%2011_MILES'
or column_name like '%2012_MILES')
order by column_id;
我怀疑这是一个家庭作业问题。重要的是你要意识到真正的教训是:数据建模非常重要,非规范化非常糟糕
甚至表的列的命名方式也很糟糕:如果将它们命名为MILES\u 2010\u 01、MILES\u 2010\u 02等会更好,因为至少这样您可以将动态查询编写为
where column_name between 'MILES_2010_01' and 'MILES_2012_12'
使用一个正确建模的表(即每个月的记录和两列每月的英里数和每月的燃气量),查询将如下所示:
SELECT t.DRIVERID
FROM BBI_BC.TRUCKS t
WHERE t.year between 2010 and 2012
group by t.driverid having sum(t.monthly_miles) >43000
如果值可以包含空值,则需要使用COALESCE或NVL:
如果要自动生成查询,请执行以下操作:
SELECT 'SELECT DRIVERID
FROM BBI_BC.TRUCKS
WHERE ' || LISTAGG( 'COALESCE( ' || TO_CHAR( ADD_MONTHS( DATE '2010-01-01', LEVEL - 1 ), 'MON_YYYY' ) || '_MILES, 0)', '
+ ' ) WITHIN GROUP ( ORDER BY LEVEL ) || ' > 430000;' AS sql
FROM DUAL
CONNECT BY ADD_MONTHS( DATE '2010-01-01', LEVEL - 1 ) <= DATE '2012-12-01';
这是一个类似于APC的解决方案,但会动态返回结果。为12c工作+
DECLARE
miles_cond VARCHAR2(20) := ' > 43000';
v_where VARCHAR2(1000);
x SYS_REFCURSOR;
BEGIN
SELECT
' WHERE '
||
LISTAGG(column_name,' + ') WITHIN GROUP(
ORDER BY
column_name
)
|| miles_cond
INTO v_where
FROM
all_tab_columns
WHERE
owner = 'BBI_BC'
AND table_name = 'TRUCKS'
AND REGEXP_LIKE ( column_name,
'201[0-2]_MILES' )
ORDER BY
column_id;
OPEN x FOR 'SELECT * FROM TRUCKS' || v_where;
dbms_sql.return_result(x);
END;
/
当然,您可以添加类似MT0的逻辑来处理空值。不要使用图片,而是添加表定义和说明。更重要的是,你的问题是什么?你想找到驱动程序,你有一个查询,你认为它返回了错误的数据还是什么?这会起作用,那么你的问题是什么?如果是如何避免键入所有这些列,答案是你不能。该表的设计者选择忽略了公认的行业标准规则。他们这样做的原因无关紧要:结果是每个查询表的人都必须编写冗长且难以维护的查询。@APC不是一种冗长的方法,我在寻找更多的通用方法来查找结果。您使用的是哪种数据库模型?您的表是否每月都会增加新的列?我建议您与架构师一起检查该模型,这有点奇怪可能您可以创建一个包含unpivot子句的视图,以便它以标准化格式显示数据,其中包含日期列,或者单独的年和月列。然后你就可以对你想要的任何时间段的里程数列求和。如何得到我所问的特定查询结果?你必须把它写出来。您所能做的就是通过查询数据字典来生成一些代码,从而为自己节省一些输入。我故意避免使用动态SQL路由,因为它不是查询。如果我正确地认为这是一个家庭作业问题,我想老师会惊讶地看到一个学生提交了这样的问题。@APC:嗯,答案已经发布了,我现在不能做太多:-。我希望将来有一天他的老板会给他分配一项任务——更复杂的SQL,我不会来这里回答。
SELECT DRIVERID
FROM BBI_BC.TRUCKS
WHERE COALESCE( JAN_2010_MILES, 0)
+ COALESCE( FEB_2010_MILES, 0)
+ COALESCE( MAR_2010_MILES, 0)
+ COALESCE( APR_2010_MILES, 0)
+ COALESCE( MAY_2010_MILES, 0)
+ COALESCE( JUN_2010_MILES, 0)
+ COALESCE( JUL_2010_MILES, 0)
+ COALESCE( AUG_2010_MILES, 0)
+ COALESCE( SEP_2010_MILES, 0)
+ COALESCE( OCT_2010_MILES, 0)
+ COALESCE( NOV_2010_MILES, 0)
+ COALESCE( DEC_2010_MILES, 0)
+ COALESCE( JAN_2011_MILES, 0)
+ COALESCE( FEB_2011_MILES, 0)
+ COALESCE( MAR_2011_MILES, 0)
+ COALESCE( APR_2011_MILES, 0)
+ COALESCE( MAY_2011_MILES, 0)
+ COALESCE( JUN_2011_MILES, 0)
+ COALESCE( JUL_2011_MILES, 0)
+ COALESCE( AUG_2011_MILES, 0)
+ COALESCE( SEP_2011_MILES, 0)
+ COALESCE( OCT_2011_MILES, 0)
+ COALESCE( NOV_2011_MILES, 0)
+ COALESCE( DEC_2011_MILES, 0)
+ COALESCE( JAN_2012_MILES, 0)
+ COALESCE( FEB_2012_MILES, 0)
+ COALESCE( MAR_2012_MILES, 0)
+ COALESCE( APR_2012_MILES, 0)
+ COALESCE( MAY_2012_MILES, 0)
+ COALESCE( JUN_2012_MILES, 0)
+ COALESCE( JUL_2012_MILES, 0)
+ COALESCE( AUG_2012_MILES, 0)
+ COALESCE( SEP_2012_MILES, 0)
+ COALESCE( OCT_2012_MILES, 0)
+ COALESCE( NOV_2012_MILES, 0)
+ COALESCE( DEC_2012_MILES, 0) > 430000;
DECLARE
miles_cond VARCHAR2(20) := ' > 43000';
v_where VARCHAR2(1000);
x SYS_REFCURSOR;
BEGIN
SELECT
' WHERE '
||
LISTAGG(column_name,' + ') WITHIN GROUP(
ORDER BY
column_name
)
|| miles_cond
INTO v_where
FROM
all_tab_columns
WHERE
owner = 'BBI_BC'
AND table_name = 'TRUCKS'
AND REGEXP_LIKE ( column_name,
'201[0-2]_MILES' )
ORDER BY
column_id;
OPEN x FOR 'SELECT * FROM TRUCKS' || v_where;
dbms_sql.return_result(x);
END;
/