我有一个历史记录,每次更改1个值时记录1行。因此,在每一行中,应始终只有1个值与上一行
相比发生了变化我的表看起来像这样。 (我有超过5列,他们没有通用名称,这些列名将为每个项目更改。我想避免硬编码列名称)
INDEX|Column1|Column2|Column3|Column4|Column5|TimeStamp
1 | 0| 0| 0| 0| 0|2017-03-28 13:00:00
2 | 0| 0| 0| 1| 0|2017-03-28 14:00:00
3 | 2| 0| 0| 1| 0|2017-03-28 15:00:00
4 | 3| 0| 0| 1| 0|2017-03-28 16:00:00
5 | 3| 22| 0| 1| 0|2017-03-28 17:00:00
6 | 3| 22| 6| 1| 0|2017-03-28 18:00:00
我想在报告中得到的结果。
Name |NewValue|PreviousValue|TimeStamp
Column4| 1| 0|2017-03-28 14:00:00
Column1| 2| 0|2017-03-28 15:00:00
Column1| 3| 2|2017-03-28 16:00:00
Column2| 22| 0|2017-03-28 17:00:00
Column3| 6| 0|2017-03-28 18:00:00
实现这一目标的最佳方式是什么?
我正在使用MariaDB 10.1.22。
答案 0 :(得分:0)
SELECT 'Column5', column5, max(timestamp) from mytable where column5 <> 0 group by column5
Union
SELECT 'Column4', column4, max(timestamp) from mytable where column4 <> 0 group by column4
Union
SELECT 'Column3', column3, max(timestamp) from mytable where column3 <> 0 group by column3
Union
SELECT 'Column2', column2, max(timestamp) from mytable where column2 <> 0 group by column2
Union
SELECT 'Column1', column1, max(timestamp) from mytable where column1 <> 0 group by column1
答案 1 :(得分:0)
这是您想要的基本代码。但一切都是硬编码的。没有“动态SQL”,这是无法避免的。
language: perl
perl:
- "5.22"
matrix:
fast_finish: true
allow_failures:
- env: COVERAGE=1 USE_CPANFILE_SNAPSHOT=true
- env: USE_CPANFILE_SNAPSHOT=false HARNESS_VERBOSE=1
env:
global:
# Carton --deployment only works on the same version of perl
# that the snapshot was built from.
- DEPLOYMENT_PERL_VERSION=5.22
- DEVEL_COVER_OPTIONS="-ignore ^local/"
matrix:
# Get one passing run with coverage and one passing run with Test::Vars
# checks. If run together they more than double the build time.
- COVERAGE=1 USE_CPANFILE_SNAPSHOT=true
- USE_CPANFILE_SNAPSHOT=false HARNESS_VERBOSE=1
- USE_CPANFILE_SNAPSHOT=true
before_install:
- git clone git://github.com/travis-perl/helpers ~/travis-perl-helpers
- source ~/travis-perl-helpers/init
- npm install -g less js-beautify
# Pre-install from backpan to avoid upgrade breakage.
- cpanm -n http://cpan.metacpan.org/authors/id/M/ML/MLEHMANN/common-sense-3.6.tar.gz
- cpanm -n App::cpm Carton
install:
- cpan-install --coverage # installs converage prereqs, if enabled
- 'cpm install `test "${USE_CPANFILE_SNAPSHOT}" = "false" && echo " --resolver metadb" || echo " --resolver snapshot"`'
before_script:
- coverage-setup
script:
# Devel::Cover isn't in the cpanfile
# but if it's installed into the global dirs this should work.
- carton exec prove -lr -j$(test-jobs) t
after_success:
- coverage-report
notifications:
email:
recipients:
- olaf@seekrit.com
on_success: change
on_failure: always
irc: "irc.perl.org#metacpan-travis"
# Use newer travis infrastructure.
sudo: false
cache:
directories:
- local
如果列之前或之后的列可能为SELECT
CASE
WHEN t1.Column1 <> t2.Column1 THEN 'Column1'
WHEN t1.Column2 <> t2.Column2 THEN 'Column2'
WHEN t1.Column3 <> t2.Column3 THEN 'Column3'
WHEN t1.Column4 <> t2.Column4 THEN 'Column4'
WHEN t1.Column5 <> t2.Column5 THEN 'Column5'
END as Name,
CASE
WHEN t1.Column1 <> t2.Column1 THEN t2.Column1
WHEN t1.Column2 <> t2.Column2 THEN t2.Column2
WHEN t1.Column3 <> t2.Column3 THEN t2.Column3
WHEN t1.Column4 <> t2.Column4 THEN t2.Column4
WHEN t1.Column5 <> t2.Column5 THEN t2.Column5
END as NewValue,
CASE
WHEN t1.Column1 <> t2.Column1 THEN t1.Column1
WHEN t1.Column2 <> t2.Column2 THEN t1.Column2
WHEN t1.Column3 <> t2.Column3 THEN t1.Column3
WHEN t1.Column4 <> t2.Column4 THEN t1.Column4
WHEN t1.Column5 <> t2.Column5 THEN t1.Column5
END as PreviousValue,
t2.TimeStamp
FROM
MyTable t1
JOIN MyTable t2
ON t2.Index = t1.Index + 1
,则需要相应地调整NULL
。
您可以通过从<>
表中提取列数据来生成上述代码,而不是对列名进行硬编码。将information_schema
变量设置为您要处理的表的名称,此代码将变量@tablename
设置为保存与上述代码相同的代码。我已使用@sql
添加新行,因此改进了生成代码中的格式。
\n
如果您对变量中的内容感到满意,可以重新运行替换最后一行:
-- Avoids the GROUP_CONCAT truncating the code we're building
SET SESSION GROUP_CONCAT_MAX_LEN=65535;
-- Specify your target table here
SELECT @tablename := 'MyTable';
SELECT @sql := GROUP_CONCAT(theCode SEPARATOR '')
FROM
(
-- theOrderBy is for keeping the various parts of this code in the correct sequence
-- SELECT plus the opening of the first CASE statement
SELECT 0 theOrderBy, 'SELECT\nCASE\n' theCode
UNION ALL
-- Generates the inner part first CASE statement
SELECT 1, CONCAT(' WHEN t1.',Column_Name,' <> t2.',Column_Name,' THEN ''', Column_Name,'''','\n')
FROM `information_schema`.`Columns`
WHERE table_name like @tablename
AND Column_Name NOT IN ('Index','Timestamp')
UNION ALL
-- Generates the end of the first CASE (and it's alias) and the beginning of the second one
SELECT 2, 'END as Name,\nCASE\n'
UNION ALL
-- Generates the inner part second CASE statement
SELECT 3, CONCAT(' WHEN t1.',Column_Name,' <> t2.',Column_Name,' THEN t2.', Column_Name, '\n')
from `information_schema`.`Columns`
WHERE table_name LIKE @tablename
AND Column_Name NOT IN ('Index','Timestamp')
UNION ALL
-- Generates the end of the second CASE (and it's alias) and the beginning of the third one
SELECT 4, 'END as NewValue,\nCASE\n'
UNION ALL
-- Generates the inner part third CASE statement
SELECT 5, CONCAT(' WHEN t1.',Column_Name,' <> t2.',Column_Name,' THEN t1.', Column_Name, '\n')
FROM `information_schema`.`Columns`
WHERE table_name like @tablename
AND Column_Name NOT IN ('Index','Timestamp')
UNION ALL
-- Generates the end of the final CASE statement plus the FROM clause
SELECT 6, CONCAT('END as PreviousValue,\nt2.Timestamp\nFROM\n ',@tablename, ' t1\n JOIN ',@tablename, ' t2 ON\n t2.Index = t1.Index + 1')
ORDER BY theOrderBy
) as sub;
SELECT @sql;
此代码的可行性在很大程度上取决于您对任何目标表具有相同的基本结构,即顺序增加PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
字段和Index
。与“静态”代码一样,这也是使用Timestamp
进行所有比较,因此有效地假设每次更改之前或之后字段都不是<>
。
如果这些假设不成立,您需要进行调整。如果您需要帮助,请告诉我。