【问题标题】:Merging two columns from two tables in PL/SQL在 PL/SQL 中合并两个表中的两列
【发布时间】:2011-08-01 18:25:38
【问题描述】:

我在尝试合并 PL/SQL 中两个表中的两列时遇到了极大的困难。我从早上 9:00 开始一直在做这件事,我放弃了,请帮助我。

目的

我想创建一个新表(称为 temp)。这会将来自两个不同表中其他两列的信息合并。

到目前为止的代码

CREATE TABLE temp
    (
        temptimeKey           CHAR(24) NOT NULL ,
        temptimeHour          INTEGER NULL ,
        temptimeMinute        INTEGER NULL ,
        temptimeSecond        INTEGER NULL ,
        temptimeMonth         INTEGER NULL ,
        temptimeDay           INTEGER NULL ,
        temptimeYear          INTEGER NULL ,
        temptimeQuarter       INTEGER NULL ,
        CONSTRAINT  XPKTEMPTIME PRIMARY KEY (temptimeKey)
    );

    insert into temp
    SELECT 
        TO_CHAR(busFareDate, 'MM/DD/YYYY HH:MM:SS Q'),
        TO_NUMBER(TO_CHAR(busFareDate, 'HH12')),
        TO_NUMBER(TO_CHAR(busFareDate, 'MI')),
        TO_NUMBER(TO_CHAR(busFareDate, 'SS')), 
        TO_NUMBER(TO_CHAR(busFareDate, 'MM')),
        TO_NUMBER(TO_CHAR(busFareDate, 'DD')),
        TO_NUMBER(TO_CHAR(busFareDate, 'YYYY')),
        TO_NUMBER(TO_CHAR(busFareDate, 'Q'))
    FROM 
        bus_fare
    UNION
    SELECT
        TO_CHAR(trainFareDate, 'MM/DD/YYYY HH:MM:SS Q'),
        TO_NUMBER(TO_CHAR(trainFareDate, 'HH12')),
        TO_NUMBER(TO_CHAR(trainFareDate, 'MI')),
        TO_NUMBER(TO_CHAR(trainFareDate, 'SS')), 
        TO_NUMBER(TO_CHAR(trainFareDate, 'MM')),
        TO_NUMBER(TO_CHAR(trainFareDate, 'DD')),
        TO_NUMBER(TO_CHAR(trainFareDate, 'YYYY')),
        TO_NUMBER(TO_CHAR(trainFareDate, 'Q'))
    FROM 
        train_fare;

    drop table temp cascade constraints;

到目前为止,这段代码只给了我一个违反唯一约束的行为:

ERROR at line 1:
ORA-00001: unique constraint (OPS$FNAVA.XPKTEMPTIME) violated

你能发现我做错了什么吗? (欢迎任何帮助)

【问题讨论】:

  • 您看到的错误是什么?什么不起作用?另外,我在这里没有看到任何 PL/SQL,但就这样吧。
  • 在每个SELECTS 的末尾尝试GROUP BY TO_CHAR(trainFareDate, 'MM/DD/YYYY HH:MM:SS Q'), TO_NUMBER(TO_CHAR(trainFareDate, 'HH12')), TO_NUMBER(TO_CHAR(trainFareDate, 'MI')), TO_NUMBER(TO_CHAR(trainFareDate, 'SS')), TO_NUMBER(TO_CHAR(trainFareDate, 'MM')), TO_NUMBER(TO_CHAR(trainFareDate, 'DD')), TO_NUMBER(TO_CHAR(trainFareDate, 'YYYY')), TO_NUMBER(TO_CHAR(trainFareDate, 'Q'))
  • 是的,我很晚才注意到我没有复制错误。所以我对其进行了编辑并附加了它。请按 F5 :)
  • 我会试试 Lamak,等一下 :)
  • 尝试将 HH 和 HH12 替换为 HH24。也许您有两个相隔 12 小时的日期导致了问题。

标签: sql oracle join union ora-00001


【解决方案1】:

试试这个:

insert into temp
SELECT 
    TO_CHAR(busFareDate, 'MM/DD/YYYY HH:MI:SS Q'),
    TO_NUMBER(TO_CHAR(busFareDate, 'HH12')),
    TO_NUMBER(TO_CHAR(busFareDate, 'MI')),
    TO_NUMBER(TO_CHAR(busFareDate, 'SS')), 
    TO_NUMBER(TO_CHAR(busFareDate, 'MM')),
    TO_NUMBER(TO_CHAR(busFareDate, 'DD')),
    TO_NUMBER(TO_CHAR(busFareDate, 'YYYY')),
    TO_NUMBER(TO_CHAR(busFareDate, 'Q'))
FROM (
        SELECT busFareDate 
        FROM bus_fare 
        GROUP BY busFareDate
        UNION
        SELECT trainFareDate 
        FROM train_fare 
        GROUP BY trainFareDate) AS Dates
GROUP BY TO_CHAR(busFareDate, 'MM/DD/YYYY HH:MI:SS Q'),
        TO_NUMBER(TO_CHAR(busFareDate, 'HH12')),
        TO_NUMBER(TO_CHAR(busFareDate, 'MI')),
        TO_NUMBER(TO_CHAR(busFareDate, 'SS')), 
        TO_NUMBER(TO_CHAR(busFareDate, 'MM')),
        TO_NUMBER(TO_CHAR(busFareDate, 'DD')),
        TO_NUMBER(TO_CHAR(busFareDate, 'YYYY')),
        TO_NUMBER(TO_CHAR(busFareDate, 'Q'));

【讨论】:

  • 没注意到他在每一列中都使用相同的列,很好。
  • @Overseer10 - 那么你必须有彼此相隔毫秒的日期。更新了我的答案,所以现在试试,让我知道结果如何。
  • @Lamak - 尝试了同样的问题。是的,该数据库是芝加哥交通管理局 ODBS 的复制品。所以信息可以详细到毫秒,我在一些表上有超过 420k 行。
  • TO_CHAR(busFareDate, 'MM/DD/YYYY HH24:MM:SS Q')。如果这不起作用,那么 TO_CHAR(busFareDate, 'MM/DD/YYYY HH24:MM:SSSSS Q')。这会将您带到 24 个字符的表定义。
  • @Overseer10 - 也许这一切都是因为我们使用 HH: MM :SS 而不是 HH: MI :SS。更新答案,再试一次。
【解决方案2】:

奇怪的是,UNION 应该会自动删除重复项。这是在 Oracle DBMS 上吗?

UNIQUE CONSTRAINT 违反错误是由于您的查询为您要插入的表中的键列返回多行。

在您的情况下, TO_CHAR(trainFareDate, 'MM/DD/YYYY HH:MM:SS Q') 将被插入到键列中。如果有两行具有相同的 MM/DD/YYYY HH:MM:SS Q,您将收到此错误,假设您的 DBMS 确实在执行“UNION ALL”。

您可以在主键中添加第二列,可以将其命名为“SOURCE”并使用“BUS”或“TRAIN”填充它。

或者,您可以对表进行完全外部联接。

SELECT coalesce(busFareDate, trainFareDate) from
bus_fare FULL OUTER JOIN train_fare ON 
   (bus_fare.busFareDate = train_fare.trainFareDate);

然后使用它作为子查询来执行您需要在日期上做的所有工作。

编辑:

我认为您的真正问题可能来自使用 HH / HH12。

如果你这样做会怎样:

SELECT 
    TO_CHAR(fareDate , 'MM/DD/YYYY HH24:MI:SS Q'),
    TO_NUMBER(TO_CHAR(fareDate , 'HH24')),
    TO_NUMBER(TO_CHAR(fareDate , 'MI')),
    TO_NUMBER(TO_CHAR(fareDate , 'SS')), 
    TO_NUMBER(TO_CHAR(fareDate , 'MM')),
    TO_NUMBER(TO_CHAR(fareDate , 'DD')),
    TO_NUMBER(TO_CHAR(fareDate , 'YYYY')),
    TO_NUMBER(TO_CHAR(fareDate , 'Q'))
 FROM 
    (SELECT coalesce(busFareDate, trainFareDate) fareDate from
     bus_fare FULL OUTER JOIN train_fare ON 
     (bus_fare.busFareDate = train_fare.trainFareDate));

【讨论】:

  • 是的,我认为 UNION 会像在 Oracle DBMS(我使用的)上那样工作。可悲的是,将 TRAIN 或 BUS 添加为列或标识符会导致以后出现问题。不过谢谢:S
  • 我很早就尝试了合并,现在按照您使用它的方式进行了尝试,结果相同。我的想法用完了
  • 我很早就对此有类似的担忧:HH24 是否会成为问题。但默认情况下,TIMESTAMP 将其作为 HH12,并以 AM 或 PM 结尾。除此之外,我还制作了一个数据测试样本,该样本只有早上 7 点到 11 点之间的时间。我尝试在两者中插入,问题仍然存在于 uninque 约束违规
  • 查看 Lamak 的 cmets - 我敢打赌这是 HH:MM 与 HH:MI 的问题。
【解决方案3】:

您的巴士票价和时间票价必须具有相同的日期/时间才能违反限制。为什么不尝试添加一个 GUID 列作为 temp Table 的主键,并使用 newid() 在联合的每一侧生成值。

【讨论】:

  • 是的,两列之间有大量重复项。我认为 UNION 会消除重复项,但事实并非如此。
  • 另外,我需要 timeKey 作为主键。不能使用 GUID(即使它更容易)。
  • Union 不仅仅适用于键列,它适用于整个结果集。如果您只处理一列(timeKey),它会按您的想法工作。
  • 所以我的总体建议是删除唯一约束,在键上添加其他内容,或者从 trainFareDate 中选择 TO_CHAR(trainFareDate, 'MM/DD/YYYY HH:MM:SS Q' ) 不在 (SELECT TO_CHAR(busFareDate, 'MM/DD/YYYY HH:MM:SS Q') from bus_fare)
  • 在他的情况下,整个结果集应该是相同的,因为它都基于那一列。
【解决方案4】:

尝试在 TO_CHAR() 周围添加 TRIM(),如下所示:

TRIM(TO_CHAR(busFareDate, 'MM/DD/YYYY HH:MI:SS Q'))

我想我记得 TO_CHAR 有时会在您可能没想到的地方添加空格填充。如果空格填充导致总长度超过 24 个字符,那么它将在进入临时表中的目标列时被截断,这会使没有重复时看起来有重复(即它们是不同的仅在最后 2 或 3 个字符中,被截断)。

或者,将 CHAR(24) 列扩展为更大的值,例如 CHAR(1000),以查看问题是否消失。

【讨论】:

  • 是的,某些格式会添加空格填充。但是如果生成的字符串的长度大于 24 个字符,它将 not 被截断。它将引发 VALUE_ERROR。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-14
相关资源
最近更新 更多