MySQL查询获取动态列及其值

时间:2017-06-27 22:57:48

标签: mysql

我有一个复杂的数据库结构。我试图解决它,但无法做到这一点。

我有五张桌子:

    获取办公室名称的
  1. User表格和office_id
  2. Service_list,其中包含所有服务名称
  3. Service,其中包含基于办公室ID的所有服务信息
  4. Service_trasaction,我们从中获取所有基于id(service.service_id = service_transaction.id)的服务。
  5. 现在我需要这样的输出:

    [office_name] [count recipients] [service_1] [service_2] .........
    =======================================================================
    Dhaka               5                4            2
    Ctg                 0                5            0
    Khulna              2                2            0
    

    目前,我只能使用此查询获取办公室名称和总收件人数:

    SELECT u.id, u.office_name, COUNT(r.id) AS `count`
    FROM users u LEFT JOIN recipient r ON u.id = r.office_id
    where(u.type = 'agency' and u.del_status = 0)
    GROUP BY u.id, u.office_name;
    

    以下是所有表格的结构:

    CREATE TABLE `recipient` (
      `id` int(10) NOT NULL,
      `name` varchar(100) NOT NULL,
      `gender` varchar(10) NOT NULL,
      `mobile` varchar(15) NOT NULL,
      `age` int(10) NOT NULL,
      `reg_no` varchar(10) NOT NULL,
      `address` varchar(255) NOT NULL,
      `disability_type` int(10) NOT NULL,
      `education` varchar(255) NOT NULL,
      `office_id` int(10) NOT NULL,
      `del_status` tinyint(1) NOT NULL,
      `create_date` date NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;      
    
     CREATE TABLE `users` (
      `id` tinyint(4) NOT NULL,
      `office_name` varchar(255) DEFAULT NULL,
      `district_id` int(10) DEFAULT NULL,
      `upazilla_id` int(10) DEFAULT NULL,
      `address` varchar(255) DEFAULT NULL,
      `mobile` varchar(11) DEFAULT NULL,
      `email` varchar(50) DEFAULT NULL,
      `username` varchar(50) NOT NULL,
      `password` varchar(100) NOT NULL,
      `type` varchar(10) NOT NULL,
      `del_status` tinyint(1) NOT NULL
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
    
    CREATE TABLE `service` (
      `id` int(10) NOT NULL,
      `recipient_number` int(50) NOT NULL,
      `date` date NOT NULL,
      `office_id` int(10) NOT NULL,
      `del_status` tinyint(1) NOT NULL,
      `creation_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    
    CREATE TABLE `service_list` (
      `id` int(3) NOT NULL,
      `service_name` varchar(50) NOT NULL,
      `del_status` tinyint(1) NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    
    CREATE TABLE `service_transaction` (
      `id` int(10) NOT NULL,
      `service_transaction_id` int(50) NOT NULL,
      `service_id` int(20) NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    

    这里是sql dump file链接:https://file.town/download/cez6u43ikr84by4xrzm34pjrf

1 个答案:

答案 0 :(得分:0)

听起来你正试图转动SQL查询的结果,或者生成一个矩阵,其中一个表创建行而另一个表创建列。

如果行和列都是任意列表,则无法执行此操作。如果列是任意列表但是行是固定的,那么在MySQL中也不能这样做,因为MySQL没有PIVOT函数。

如果有一定数量的列被认为不会改变(或者每当其中一个更改时都可以编辑SQL语句),那么您可以通过手动构建聚合函数中的每个列来实现此目的,但它在查询中变得非常混乱,你真的必须考虑你正在做的事情来实现它。

在您的具体示例中,类似这样的方法就是:

SELECT
    office_name,
    COUNT(*) as count_recipients,
    SUM(service.id = 1) AS service_1,
    SUM(service.id = 2) AS service_2,
    ...
    SUM(service.id = n) AS service_n
FROM
    ...etc...
GROUP BY
    office_name

正如您所看到的,您无法自动创建这些服务列 - 您必须为每个service.id执行一个服务。最好的情况是,您的软件可以获得所有服务ID的完整列表,并以编程方式使用每个服务ID的列构建查询,但是您可以在查询中返回的列数有限制,因此这只会如此远。

更好的解决方案是在您的演示代码中处理显示,而不是在数据库查询中处理(正如您在上述问题的评论中以令人愉快的命名草莓所示)。