我们正在尝试构建用于Tableau的数据库的非规范化版本。我们面临的挑战之一是在我们的一个表中处理我们的键/值对。请参阅以下某些数据的简化版本。
Asset Table
Asset ID Site ID Make Model
1 1 Toyota Corolla
2 2 Honda Civic
3 2 Suzuki Swift
Asset Property Types Table
Site ID Asset Property Name Asset Property Type
1 Odometer Numeric
1 Registration Text
1 Expiry Date Date
2 Odometer Numeric
2 Registration Text
2 Expiry Date Date
2 Colour Text
Asset Properties Table
Asset ID Key Text Value Numeric Value Date Value
1 Odometer 1234
1 Registration ABC123
1 Expiry Date 2018-02-08
2 Odometer 1255
2 Registration ABC124
2 Colour Red
2 Expiry Date 2018-01-08
3 Registration ABC125
3 Odometer 1266
3 Colour Blue
3 Expiry Date 2018-03-25
有一点需要注意。这是数据的简化版本。并非所有资产都具有相同的键/值对。网站将包含他们想要存储的各种数据类型,这些数据类型可能与其他网站不同。
最终,这是我们想要尝试和实现的目标:
Site 1 Asset Table
Asset ID Make Model Odometer Registration Expiry Date
1 Toyota Corolla 1234 ABC123 2018-02-08
Site 2 Asset Table
Asset ID Make Model Odometer Registration Expiry Date Colour
2 Honda Civic 1255 ABC124 2018-01-08 Red
3 Suzuki Swift 1266 ABC125 2018-03-25 Blue
我对此的一般处理如下:
我希望通过MySQL过程完成所有这些操作,以便我可以安排它每小时自动运行并替换各种站点级别表。 CASE语句不起作用,因为这需要是动态的。
我非常感谢有关如何实现这一目标的任何建议/帮助。虽然我对SQL很满意,但程序远非我的深度。
答案 0 :(得分:1)
我想难以理解的是构建动态案例陈述。因此,给出您的数据(通过一些更改来删除空格和可能的关键字冲突)
create table Asset(Asset_ID int, Site_ID int, Make varchar(20), Model varchar(20));
insert into asset values
(1 , 1 , 'Toyota' , 'Corolla'),
(2 , 2 , 'Honda' , 'Civic'),
(3 , 2 , 'Suzuki' , 'Swift');
drop table if exists Asset_Property_Types;
create table Asset_Property_Types (Site_ID int, Asset_Property_Name varchar(100), Asset_Property_Type varchar(100));
insert into asset_property_types values
(1 , 'Odometer' , 'Numeric_value'),
(1 , 'Registration' , 'Text_value'),
(1 , 'Expiry_Date' , 'Date_value'),
(2 , 'Odometer' , 'Numeric_value'),
(2 , 'Registration' , 'Text_value'),
(2 , 'Expiry_Date' , 'Date_value'),
(2 , 'Colour' , 'Text_value');
create table Asset_Properties(Asset_ID int , asset_property_name varchar(30),Text_Value varchar(100), Numeric_Value int , Date_Value date);
insert into asset_properties values
(1 , 'Odometer' , null , 1234 ,null),
(1 , 'Registration' , 'ABC123' ,null ,null),
(1 , 'Expiry_Date' , null , null, '2018-02-08'),
(2 , 'Odometer' , null , 1255 ,null),
(2 , 'Registration' , 'ABC124' ,null ,null),
(2 , 'Colour' , 'Red' ,null ,null),
(2 , 'Expiry_Date' , null , null ,'2018-01-08'),
(3 , 'Registration' , 'ABC125' ,null ,null),
(3 , 'Odometer' , null , 1266,null),
(3 , 'Colour' , 'Blue' ,null ,null),
(3 , 'Expiry_Date' , null , null ,'2018-03-25');
此代码
set @sql = (select concat('select a.asset_id ,a.site_id,a.make,a.model,',
group_concat(
concat('max(case when asset_property_name = ' ,char(39),asset_property_name,char(39), ' then ' ,asset_property_type ,' else null end) as ', asset_property_name)
)
,' from asset a join asset_properties ap on ap.asset_id = a.asset_id group by a.site_id,a.asset_id;'
)
from
(select distinct asset_property_name,asset_property_type from asset_property_types) a
)
;
构建此sql语句
select a.asset_id ,a.site_id,a.make,a.model,
max(case when asset_property_name = 'Odometer' then Numeric_value else null end) as Odometer,
max(case when asset_property_name = 'Registration' then Text_value else null end) as Registration,
max(case when asset_property_name = 'Expiry_Date' then Date_value else null end) as Expiry_Date,
max(case when asset_property_name = 'Colour' then Text_value else null end) as Colour
from asset a join asset_properties ap on ap.asset_id = a.asset_id
group by a.site_id,a.asset_id;
然后您可以将其提交给sql,如此
prepare sqlstmt from @sql;
execute sqlstmt;
deallocate prepare sqlstmt;
答案 1 :(得分:0)
您的问题类似于数据透视表问题。您可以谷歌搜索以找到解决它的更多变体。解决这个问题的一种方法是
A)获取列名称
`Select distinct key from assetPropertiesTable;`
B)使用动态SQL构建一个Select查询字符串,对于上一个查询中的每个键k,它都有一个使用子选择的列,如
(select textvalue from assetPropertiesTable t where t.id = outerselect.id and key = k) as column_k
C)执行完整查询并从存储过程返回它或执行create table xyz as /*select query here*/
。
无需分两步创建和填充表格。
有更多区别且更高效的方法,例如加入assetPropertiesTable一次,并对要添加的每列的布尔条件key=k
进行求和