mysql:用于计算在一个数据范围内发现几个月的最后一天的次数的查询

30byixjq  于 2021-06-18  发布在  Mysql
关注(0)|答案(2)|浏览(240)

我有一个数据库记录客户合同。每个合同都有一个有效期,它作为日期存储在合同开始和合同结束中。
我想创建一个视图,在每个月底显示每个客户上有多少合同处于活动状态。
下面的查询显示了执行此操作的愚蠢方式,我想知道是否可以创建一个自动执行此操作的“循环”:

  1. SELECT
  2. '2018-01-31' AS snapshot_day,
  3. customer,
  4. COUNT(*) AS active_contracts
  5. FROM
  6. my_table
  7. WHERE
  8. contract_start < '2018-02-01'
  9. AND contract_end >= '2018-02-01'
  10. GROUP BY 2
  11. UNION SELECT
  12. '2018-02-28' AS snapshot_day,
  13. customer,
  14. COUNT(*) AS active_contracts
  15. FROM
  16. my_table
  17. WHERE
  18. contract_start < '2018-03-01'
  19. AND contract_end >= '2018-03-01'
  20. GROUP BY 2
  21. UNION SELECT
  22. '2018-03-30' AS snapshot_day,
  23. customer,
  24. COUNT(*) AS active_contracts
  25. FROM
  26. my_table
  27. WHERE
  28. contract_start < '2018-04-01'
  29. AND contract_end >= '2018-04-01'
  30. GROUP BY 2
  31. .
  32. .
  33. .
  34. and so on

样本输入:

  1. customer | contract_start | contract_end
  2. CustA | 2018-01-22 | 2019-01-22
  3. CustA | 2018-03-15 | 2019-03-15
  4. CustA | 2018-07-10 | 2019-07-10
  5. CustA | 2018-09-08 | 2018-12-10
  6. CustB | 2018-02-17 | 2018-11-17
  7. CustB | 2018-05-13 | 2019-05-13
  8. CustB | 2018-10-01 | 2019-10-01
  9. CustB | 2018-12-25 | 2019-12-25

期望输出:

  1. snapshot_day | customer | active_contracts
  2. 2018-01-31 | CustA | 1
  3. 2018-02-28 | CustA | 1
  4. 2018-03-31 | CustA | 2
  5. 2018-04-30 | CustA | 2
  6. 2018-05-31 | CustA | 2
  7. 2018-06-30 | CustA | 2
  8. 2018-07-31 | CustA | 3
  9. 2018-08-31 | CustA | 3
  10. 2018-09-30 | CustA | 4
  11. 2018-10-31 | CustA | 4
  12. 2018-11-30 | CustA | 4
  13. 2018-12-31 | CustA | 3
  14. 2018-01-31 | CustB | 0
  15. 2018-02-28 | CustB | 1
  16. 2018-03-31 | CustB | 1
  17. 2018-04-30 | CustB | 1
  18. 2018-05-31 | CustB | 2
  19. 2018-06-30 | CustB | 2
  20. 2018-07-31 | CustB | 2
  21. 2018-08-31 | CustB | 2
  22. 2018-09-30 | CustB | 2
  23. 2018-10-31 | CustB | 3
  24. 2018-11-30 | CustB | 2
  25. 2018-12-31 | CustB | 2

提前谢谢!

sulc1iza

sulc1iza1#

也可以尝试按年份和月份分组:

  1. SELECT
  2. customer,
  3. COUNT(*) AS active_contracts,
  4. MONTH(contract_start) as month,
  5. YEAR(contract_start) as year
  6. FROM
  7. my_table
  8. GROUP BY customer, year, month
x7yiwoj4

x7yiwoj42#

考虑以下几点。这并不是最优雅的解决方案,它使用了一个实用程序表,这并不是绝对必要的(如果您使用的是mysql 8或更高版本,就更不用说了)。
然而,子查询的使用有希望使解决方案的各个步骤变得相当容易。
而且,我的结果和你的不一样。这可能是因为我考虑了在一个月的最后一天有多少活跃的合同,而你实际上是在追求一些稍微不同的东西。同样,也可能是因为你犯了个错误;-)
最后,如果你想为自己制作一个日历表,有很多关于它的教程。。。

  1. DROP TABLE IF EXISTS my_table;
  2. CREATE TABLE my_table
  3. (customer VARCHAR(12) NOT NULL
  4. ,contract_start DATE NOT NULL
  5. ,contract_end DATE NOT NULL
  6. ,PRIMARY KEY(customer,contract_start)
  7. );
  8. INSERT INTO my_table VALUES
  9. ('CustA','2018-01-22','2019-01-22'),
  10. ('CustA','2018-03-15','2019-03-15'),
  11. ('CustA','2018-07-10','2019-07-10'),
  12. ('CustA','2018-09-08','2018-12-10'),
  13. ('CustB','2018-02-17','2018-11-17'),
  14. ('CustB','2018-05-13','2019-05-13'),
  15. ('CustB','2018-10-01','2019-10-01'),
  16. ('CustB','2018-12-25','2019-12-25');
  17. SELECT a.snapshot
  18. , b.customer
  19. , COUNT(*) active_contracts
  20. FROM
  21. ( SELECT DISTINCT LAST_DAY(x.dt) snapshot
  22. FROM calendar x
  23. JOIN
  24. ( SELECT LAST_DAY(MIN(contract_start)) range_start
  25. , LAST_DAY(MAX(contract_end)) range_end
  26. FROM my_table
  27. ) y
  28. ON x.dt BETWEEN range_start AND range_end
  29. ) a
  30. JOIN my_table b
  31. ON a.snapshot BETWEEN b.contract_start AND b.contract_end
  32. GROUP
  33. BY customer, snapshot
  34. ORDER
  35. BY customer, snapshot;
  36. +------------+----------+------------------+
  37. | snapshot | customer | active_contracts |
  38. +------------+----------+------------------+
  39. | 2018-01-31 | CustA | 1 |
  40. | 2018-02-28 | CustA | 1 |
  41. | 2018-03-31 | CustA | 2 |
  42. | 2018-04-30 | CustA | 2 |
  43. | 2018-05-31 | CustA | 2 |
  44. | 2018-06-30 | CustA | 2 |
  45. | 2018-07-31 | CustA | 3 |
  46. | 2018-08-31 | CustA | 3 |
  47. | 2018-09-30 | CustA | 4 |
  48. | 2018-10-31 | CustA | 4 |
  49. | 2018-11-30 | CustA | 4 |
  50. | 2018-12-31 | CustA | 3 |
  51. | 2019-01-31 | CustA | 2 |
  52. | 2019-02-28 | CustA | 2 |
  53. | 2019-03-31 | CustA | 1 |
  54. | 2019-04-30 | CustA | 1 |
  55. | 2019-05-31 | CustA | 1 |
  56. | 2019-06-30 | CustA | 1 |
  57. | 2018-02-28 | CustB | 1 |
  58. | 2018-03-31 | CustB | 1 |
  59. | 2018-04-30 | CustB | 1 |
  60. | 2018-05-31 | CustB | 2 |
  61. | 2018-06-30 | CustB | 2 |
  62. | 2018-07-31 | CustB | 2 |
  63. | 2018-08-31 | CustB | 2 |
  64. | 2018-09-30 | CustB | 2 |
  65. | 2018-10-31 | CustB | 3 |
  66. | 2018-11-30 | CustB | 2 |
  67. | 2018-12-31 | CustB | 3 |
  68. | 2019-01-31 | CustB | 3 |
  69. | 2019-02-28 | CustB | 3 |
  70. | 2019-03-31 | CustB | 3 |
  71. | 2019-04-30 | CustB | 3 |
  72. | 2019-05-31 | CustB | 2 |
  73. | 2019-06-30 | CustB | 2 |
  74. | 2019-07-31 | CustB | 2 |
  75. | 2019-08-31 | CustB | 2 |
  76. | 2019-09-30 | CustB | 2 |
  77. | 2019-10-31 | CustB | 1 |
  78. | 2019-11-30 | CustB | 1 |
  79. +------------+----------+------------------+
展开查看全部

相关问题