【问题标题】:How to create new table in PostgreSQL from existing table that has columns with distinct row values?如何从具有不同行值的列的现有表在 PostgreSQL 中创建新表?
【发布时间】:2022-08-13 03:54:19
【问题描述】:

我有桌子交易看起来像这样 -

我想做一个单独的顾客具有按升序排列的不同 \'customer_code\' 以及相关的 \'market_code\'、\'market_name\' 和 \'zone\' 列的表。 结果表看起来像这样 -

我努力了 -

create table customers as (
select customer_code, market_code, market_name, zone 
from transactions group by customer_code);

这在 MySQL 工作台上运行良好,但在 PGadmin 上不起作用。

  • PGadmin 处理 PostgreSQL,而不是 MySQL。在 PostgreSQL CREATE TABLE AS 中不允许使用括号(此外,在 MySQL 中也是如此,但 MySQL 会原谅此类错误)。
  • 我在问题中添加了屏幕截图。删除括号不起作用。即使与剩余的列进行分组也会使表中的列值不明确。
  • 删除 GROUP BY 但添加 DISTINCT。
  • SELECT DISTINCT customer_code、market_code、market_name、zone FROM 交易;它具有非不同的列值。
  • 它具有非不同的列值。似乎声称的任务和需要的任务不一样。显示这些“非不同列值”样本(对于一个明确的 customer_code)以及导致这些行的所有源行都出现在输出中。

标签: mysql sql create-table pgadmin-4


【解决方案1】:

你问两个问题:

  1. 为什么我的 create table 语句在 MySQL 而不是在 postgreSQL 中运行?
  2. 如何编写正确的创建表语句?

    MySQL 与 PostgreSQL

    关于第一个问题:您的查询无效。您按 customer_code 分组并选择 market_code。但是一个 customer_code 有很多行,那么要选择哪个 market_code 呢?你忘了告诉 DBMS。因此,两个 DBMS 都应该抛出错误。如果 MySQL 没有,这可能意味着您正在使用一个旧的 MySQL 版本,该版本设置为 MySQL 在开始时遇到GROUP BY 子句和功能依赖关系问题时发明的作弊模式。确保在 MySQL 中 SET sql_mode = 'ONLY_FULL_GROUP_BY'; 在编写此类无效查询时获得正确的语法错误消息 - 或使用默认模式为当前 MySQL 版本。

    至于第二个问题,这不是那么容易回答的……

    数据库规范化

    您正在处理一个非规范化表。它一次又一次地显示同一区域同一市场的同一客户。这很容易出错。您希望同一个客户总是在同一个市场中,但如果某些交易并非如此呢?您期望一个代码完全属于一个市场名称,但如果表中并非总是如此,该怎么办?您期望一个市场位于一个区域,同样,如果并非所有交易都属于这种情况怎么办?

    假设您的所有期望都是有效的,而违反这些期望的数据是错误的。

    纠正不一致

    所以,首先要找到数据不一致的地方。我在这里使用 PostgreSQL,因为尽管有 MySQL 标签,这似乎是您想要使用的。

    select customer_code, string_agg(distinct market_code, ',' order by market_code)
    from transactions
    group by customer_code
    having count(distinct market_code) > 1;
    

    如果此查询返回具有多个市场的客户,请修复您的数据。例如。:

    update transactions
    set market_code = 'Mark001'
    where customer_code = 'Cus001';
    

    市场代码也一样。查询:

    select market_code, string_agg(distinct market_name, ',' order by market_name)
    from transactions
    group by market_code
    having count(distinct market_name) > 1;
    

    更新不一致的数据:

    update transactions
    set market_name = 'Darbhanga'
    where market_code = 'Mark001';
    

    市场区域也一样。查询:

    select market_code, string_agg(distinct zone, ',' order by zone)
    from transactions
    group by market_code
    having count(distinct zone) > 1;
    

    更新不一致的数据:

    update transactions
    set zone = 'Bihar'
    where market_code = 'Mark001';
    

    规范化数据库

    完成后,构建您的表。是的,不仅仅是一张客户表,因为这仍然是非规范化的并且承担同样的风险。相反,我们有区域、市场、客户和交易。

    您可以使用技术 ID 或单独使用您的代码。我在这里根据您的代码构建表格,但选择权在您。

    区域

    create table zone
    (
      zone_code varchar(100) not null,
      zone      varchar(100) not null,
      primary key (zone_code),
      unique (zone)
    );
    
    insert into zone (zone_code, zone)
      select distinct upper(zone), zone
      from transactions;
    

    市场

    create table market
    (
      market_code varchar(100) not null,
      name        varchar(100) not null,
      zone_code   varchar(100) not null,
      primary key (market_code),
      unique (name),
      constraint fk_market_zone foreign key(zone_code) references zone(zone_code)
    );
    
    insert into market (market_code, name, zone_code)
      select distinct market_code, market_name, upper(zone)
      from transactions;
    

    顾客

    create table customer
    (
      customer_code varchar(100) not null,
      market_code varchar(100) not null,
      primary key (customer_code),
      constraint fk_customer_market foreign key(market_code) references market(market_code)
    );
    
    insert into customer (customer_code, market_code)
      select distinct customer_code, market_code
      from transactions;
    

    交易

    从表中删除现在多余的列。它们现在隐含在客户身上。

    alter table transactions
      drop column market_code,
      drop column market_name,
      drop column zone;
    

【讨论】:

  • 感谢您提供详细的解决方案并指出数据中的基本问题。
【解决方案2】:

据我了解,您只需要一个 DISTINCT 子句-

CREATE TABLE customers as
SELECT DISTINCT customer_code, market_code, market_name, zone 
  FROM transactions;

【讨论】:

  • 列具有非不同(重复)值
  • 您能否将该非重复数据和预期结果发布为文本而不是图像。
  • 我可以共享屏幕吗
  • @atif 如果客户代码具有非离散值,应该使用什么逻辑来确定输出?您的 MySQL 代码只是随机/任意选择要使用的一行,这就是您想要的吗?
【解决方案3】:

如果您尝试从选择 customer_code、market_code、market_name、zone 创建临时表怎么办?然后从临时表中尝试做不同的和分组依据。

【讨论】:

    【解决方案4】:

    为了让customer_code字段在这个表中具有唯一值,对于同一个customer_code,其他字段在transactions表中不能有不同的值,例如如果一个customer_code可能有不同的值​​​​在 market_code、market_name 或 zone 字段中,在 transactions 表的不同行中,因此这需要您没有考虑过的集群策略。

    GROUP BY 子句需要一些聚合函数,如 MySQL 中的 SUM、MAX、MIN、AVG 等......当你不使用任何它时,它会带来第一行,确保对 GROUP BY 中请求的内容进行分组,在 PostgreSQL 中这不会发生,未分组字段需要聚合函数。

    下面我给出了一个示例,说明如何在不创建视图或其他内容的情况下拆分表格,这样可以更轻松地解决像您的问题这样的复杂问题。也许如果您对问题更具体,则更容易给出更好的答案。

    CREATE TABLE customers AS 
    WITH STEP_A AS (
        SELECT 
            T.customer_code
            , COUNT(T.customer_code) AS TOT
        FROM
            transactions T 
        GROUP BY
            T.customer_code 
    )
    , STEP_B AS (
        SELECT 
            A.customer_code 
        FROM
            STEP_A A
        INNER JOIN 
            transactions T 
            ON A.customer_code = T.customer_code 
        WHERE 
            A.TOT = 1
    )
    
    SELECT 
        B.* 
    FROM 
        STEP_B B 
    ORDER BY
        B.customer_code ASC
    ;
    

    希望这可以帮助!!祝你好运!

    【讨论】:

    • 这将排除任何有超过一笔交易的客户。你为什么想这么做?
    • 如果您在选择中使用了 distinct 仍然带来了重复的 customer_code,这是因为其他字段之一对于同一个 customer_code 具有多个值,因此需要使用 SUM、AVG、MAX、MIN 等函数进行分组等,在不是 customer_code 的字段中。只有这样,它才会为 customer_code 字段带来唯一值。在问题中,如果同一客户有不同的值,则没有定义分组策略,只询问如何使用具有唯一客户代码的选择来制作表格。
    • 如果在 transactions 表中只有这些字段的值始终相同,那么在公共 select 中进行简单的 distinct 就可以解决它。由于他们没有要求为这些其他领域定义策略,所以我回答了这个问题,展示了它会是什么样子,而没有带来“原始问题中没有预见到的”。
    • 我同意这个问题不完整。不过,您的答案不适用于原始问题。如果一位客户有两笔交易,并且在四个相关列中具有相同的值,则该客户仍不会显示在查询的结果集中。
    【解决方案5】:

    嗨,在您的查询中添加 DISTINCT 并将所有列分组并将其保存为 csv。 PostgreSQL 稍后导入 CSV。

        SELECT DISTINCT 
           customer_code -- 1
          ,market_code   -- 2
          ,market_name   -- 3
          ,zone          -- 4
    
       FROM transactions 
       GROUP by 1,2,3,4
    

    【讨论】:

    • 使用您的代码,该列有重复项。
    【解决方案6】:

    下表创建名称为客户的表

    with cte as(
      select customer_code from transactions
        group by customer_code
      )select * into customers from cte
    

    【讨论】:

    • 如果您在此处阅读其他答案,则操作员已经说明了为什么这对他们不起作用。
    • 我正在使用结果创建表公用表表达式它会工作@MatBailie
    • 不会。操作人员在多个地方指出,他们的数据在这四列中不是唯一的,因此这将为某些客户产生重复的条目。他们没有解释他们想要实施什么逻辑来处理这个问题。无论哪种方式,OP 已经解释了为什么 CTE 中的逻辑不能满足他们的需求。
    • @MatBailie 相应地进行更改将不同的客户放入表中
    猜你喜欢
    • 2019-12-27
    • 2021-09-19
    • 1970-01-01
    • 2021-11-28
    • 2021-07-04
    • 1970-01-01
    • 1970-01-01
    • 2020-05-04
    • 1970-01-01
    相关资源
    最近更新 更多