插入变量后,MySQL程序表现得很奇怪

时间:2018-02-13 05:12:34

标签: mysql stored-procedures

我在使用MySQL时遇到了令人沮丧的时间以及我正在编写的程序,并希望了解其他人是否有任何有关正在发生的事情的线索。

我在下面的过程将动态地将表中的行转置为列。除了最后一个WHERE语句之外,它的工作正常。

如果我有以下任何一个WHERE语句,它就可以正常工作。

WHERE t.company_id = v_company_id AND t.class = 'asset_property'

WHERE t.company_id IN (v_company_id) AND t.class = 'asset_property'

但是,如果我还想获取company_id可能为1的记录,或者传递的值是什么,它就会拒绝运行。对查询进行的唯一更改是“#WHERE”语句。这些版本都不会起作用。

WHERE (t.company_id = v_company_id OR t.company_id = 1) AND t.class = 'asset_property'

WHERE t.company_id IN (v_company_id, 1) AND t.class = 'asset_property'

WHERE t.company_id IN (161, 1) AND t.class = 'asset_property'

感谢精通MySQL的人提供的任何帮助。我尽可能地尝试调试,我似乎唯一发现的错误是,当我尝试将t.company_id作为两个值中的一个时,会出现一般错误Invalid table name

完整程序如下。

(请参阅更新1)

最后,如果我生成上面的工作语句,然后手动添加t.company_id = 1条记录的行,它将完美运行并创建以下查询。

(请参阅更新1)

更新1

为了让其他人可以模拟我所看到的内容,我已经在其中构建了一个包含测试数据的测试数据库,因此您可以自己尝试一下。同时删除上面的一些代码以节省空间......

尝试在此处添加此内容会使我的角色限制爆炸。我已将其上传到我的个人网站。 (如果这不是一件安全的事情,请告诉我!) Test DB

创建此数据库之后,您可以运行一些程序和SQL语句来测试它并模拟我正在做的事情。

测试数据库中的过程fill_tableau_ap将运行,并将创建一个包含数据的表(但缺少公司1记录)。

该过程生成以下SQL:

CREATE TABLE dw_161.tableau_ap AS 
    SELECT a.id as "Asset ID (ap)", 
        max(case when ap.property_id = 2473 then ap.text_value else null end) as "Business Class" ,
        max(case when ap.property_id = 2294 then ap.date_value else null end) as "COI Date" ,
        max(case when ap.property_id = 2293 then ap.date_value else null end) as "Compliance Date" ,
        max(case when ap.property_id = 2291 then ap.text_value else null end) as "Fuel Type" ,
        max(case when ap.property_id = 2292 then ap.text_value else null end) as "Operator" ,
        max(case when ap.property_id = 2296 then ap.numeric_value else null end) as "PAX Capacity" ,
        max(case when ap.property_id = 2295 then ap.date_value else null end) as "Registration Expiry" ,
        max(case when ap.property_id = 2290 then ap.text_value else null end) as "Taxi Plate" ,
        max(case when ap.property_id = 2323 then ap.text_value else null end) as "VIN" 
    FROM dw_161.equipment AS a 
    JOIN dw_161.asset_properties ap ON ap.asset_id = a.id 
    JOIN dw_161.sites AS s on a.site_id = s.id 
    WHERE dw_161.s.company_id = 161 
    GROUP BY a.id;

如果我手动,将公司1中的单个项目添加到上面的语句中,我可以在DB上运行它,它也可以。如果您还想在测试数据库上运行它,它的外观如下。

CREATE TABLE dw_161.tableau_ap AS 
    SELECT a.id as "Asset ID (ap)", 
        max(case when ap.property_id = 2473 then ap.text_value else null end) as "Business Class" ,
        max(case when ap.property_id = 2294 then ap.date_value else null end) as "COI Date" ,
        max(case when ap.property_id = 2293 then ap.date_value else null end) as "Compliance Date" ,
        max(case when ap.property_id = 2291 then ap.text_value else null end) as "Fuel Type" ,
## Next field added manually from company 1 into the query
        max(case when ap.property_id = 213 then ap.numeric_value else null end) as "Odometer" ,
        max(case when ap.property_id = 2292 then ap.text_value else null end) as "Operator" ,
        max(case when ap.property_id = 2296 then ap.numeric_value else null end) as "PAX Capacity" ,
        max(case when ap.property_id = 2295 then ap.date_value else null end) as "Registration Expiry" ,
        max(case when ap.property_id = 2290 then ap.text_value else null end) as "Taxi Plate" ,
        max(case when ap.property_id = 2323 then ap.text_value else null end) as "VIN" 
    FROM dw_161.equipment AS a 
    JOIN dw_161.asset_properties ap ON ap.asset_id = a.id 
    JOIN dw_161.sites AS s on a.site_id = s.id 
    WHERE dw_161.s.company_id = 161 
    GROUP BY a.id;

因此我们可以得出结论,如果我能正确生成语句,它将运行并运行。因此,语句生成必定存在问题。

将程序分成几部分,下半部分将资产属性列表输入上半部分。这就是我觉得事情变得混乱的地方。具体而言,在程序的这一部分中:

    SELECT i.id as ap_id, item as ap_name, asset_property_data_type as ap_data_type
    FROM dw_161.config_items as i
    JOIN dw_161.config_tables as t on t.id = i.table_id
    WHERE t.company_id IN (v_company_id) AND t.class = 'asset_property'    
    ORDER BY ap_name

那么如果我拿出变量v_company_id并手动输入我最终寻找的并运行它,会发生什么呢,如下所示?当然,它可以工作并提供所有资产属性的列表。 (这里没有重复。

SELECT i.id as ap_id, item as ap_name, asset_property_data_type as ap_data_type
FROM dw_161.config_items as i
JOIN dw_161.config_tables as t on t.id = i.table_id
WHERE t.company_id IN (161,1) AND t.class = 'asset_property'    
ORDER BY ap_name

更新2

哎呀!!!虽然经历了所有这些并确保它对于其他人来说完全可重复,我注意到当我们将数字和十进制数据存储在一个名为的单个字段中时,其中一个字段在数据库中注册为decimal表中的numeric_value。这绝对是我的问题,我自己似乎有Rubber Ducked。更改过程以将存储在DB中的任何字段转换为实际的列名称解决了我的问题!

如果有人感兴趣,这是完成的程序。如果其他人需要将行转换为数据库中的列,这是一个有趣的代码。

BEGIN

    SET  @sql = concat('DROP TABLE IF EXISTS dw_', v_company_id, '.tableau_ap;');
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

    SET SESSION group_concat_max_len = 1000000;
    SET @sql = (select concat('CREATE TABLE dw_', v_company_id, '.tableau_ap AS SELECT a.id as "Asset ID (ap)", ',
            group_concat(
                concat('max(case when ap.property_id = ',ap_id, ' then ap.', ap_data_type, '_value else null end) as "', ap_name,'" ')
            ),
            'FROM dw_', v_company_id, '.equipment AS a ',
            'JOIN dw_', v_company_id, '.asset_properties ap ON ap.asset_id = a.id ',
            'JOIN dw_', v_company_id, '.sites AS s on a.site_id = s.id ',
            'WHERE dw_', v_company_id, '.s.company_id = ', v_company_id,' ',
            'GROUP BY a.id;'
            )
    from 
    (
        SELECT i.id as ap_id, item as ap_name, 
            (CASE asset_property_data_type
                WHEN 'numeric' THEN 'numeric'
                WHEN 'decimal' THEN 'numeric'
                WHEN 'calculated' THEN 'numeric'
                WHEN 'text' THEN 'text'
                WHEN 'date' THEN 'date'
                WHEN 'asset' THEN 'id'
                WHEN 'employee' THEN 'id'
                WHEN 'bar-code' THEN 'text'
                WHEN 'currency' THEN 'numeric'
                WHEN 'time' THEN 'date'
                WHEN 'duration' THEN 'date'
                WHEN 'serial' THEN 'text'
             END) AS ap_data_type
        FROM dw_161.config_items as i
        JOIN dw_161.config_tables as t on t.id = i.table_id
        WHERE t.company_id IN (v_company_id,1) AND t.class = 'asset_property'    
        ORDER BY ap_name) a
    )
    ;

    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;

END

1 个答案:

答案 0 :(得分:0)

请参阅原帖中的更新2