【问题标题】:select from unknown number of tables with parameter从未知数量的带有参数的表中选择
【发布时间】:2019-03-13 01:31:31
【问题描述】:

我想使用参数从多个表中选择(联合)行

我有两列表格w

table_name 列指的是我的数据库中的其他表,condition 是应该添加到查询中的“位置”。

table_name | condition 
---------------------
x          |  y=2
x          |  r=3
t          |  y=2

查询应该是这样的:

select * from x where y=2
union
select * from x where r=3
union
select * from t where y=2

当然,工会的数量是未知的。

应该是存储过程吗?光标?

【问题讨论】:

标签: mysql sql stored-procedures parameters stored-functions


【解决方案1】:

完成此任务的一种方法。最初的答案是 SQL Server 语法。此编辑具有 MySQL 语法。确保不能同时访问您的临时表。例如。在 MySQL 中,临时表对连接是唯一的。还要添加您的错误检查。在 MySQL 中,根据您的需要设置适当的 varchar 大小。我全面使用 1024 只是为了测试目的。

MySQL 语法

CREATE table test (
    id int,
    table_name varchar(1024),
    where_c varchar(1024)
);

INSERT into test(id, table_name, where_c) values
(1,'x','y=2'),
(2,'x','r=3'),
(3,'t','y=2');

DROP PROCEDURE IF EXISTS generate_sql;

DELIMITER //
CREATE PROCEDURE generate_sql()
BEGIN
DECLARE v_table_name VARCHAR(1024);
DECLARE v_where_c VARCHAR(1024);
DECLARE table_id INT;
DECLARE counter INT;
DECLARE v_SQL varchar(1024);

CREATE TEMPORARY table test_copy
SELECT * FROM test;

SET v_SQL = '';

SET counter = (SELECT COUNT(1) FROM test_copy);
WHILE counter > 0 DO
    SELECT id, table_name, where_c
    INTO table_id, v_table_name, v_where_c
    FROM test_copy LIMIT 1;

    SET v_SQL = CONCAT(v_SQL, 'SELECT * FROM ', v_table_name, ' WHERE ', v_where_c);

    DELETE FROM test_copy WHERE id=table_id;
    SET counter = (SELECT COUNT(1) FROM test_copy);

    IF counter > 0 THEN
        SET v_SQL = CONCAT(v_SQL,' UNION ');
    ELSE
        SET v_SQL = v_SQL;
    END IF;
END WHILE;

DROP table test_copy;

SELECT v_SQL;
END //
DELIMITER ;

call generate_sql()

SQL Server 语法

CREATE table test (
    id int,
    table_name varchar(MAX),
    condition varchar(MAX)
);

INSERT into test(id, table_name, condition) values
(1,'x','y=2'),
(2,'x','r=3'),
(3,'t','y=2');

SELECT * INTO #temp FROM test;

DECLARE @SQL varchar(MAX);
SET @SQL='';

while exists (select * from #temp)
begin

    DECLARE @table_name varchar(MAX);
    DECLARE @condition varchar(MAX);
    DECLARE @table_id int;

    SELECT top 1 @table_id=id, @table_name=table_name, @condition=condition FROM #temp;

    SET @SQL += 'SELECT * FROM ' + @table_name + ' WHERE ' + @condition;

    delete #temp where id = @table_id;

    if exists (select * from #temp) SET @SQL += ' UNION ';
end

SELECT @SQL;
drop table #temp;

【讨论】:

  • 这是一个 MySQL 问题的 sql server 答案。
【解决方案2】:

假设表 xt 具有相同的定义,并且您想通过使用 UNION 而不是 UNION ALL 来忽略重复的结果,以下应该可以工作:

SET @sql = '';

SELECT GROUP_CONCAT(
  CONCAT('SELECT * FROM `', `table_name`, '` WHERE ', `condition`) 
  SEPARATOR ' UNION ') INTO @sql
FROM w;

SET @sql = CONCAT('SELECT * FROM ( ', @sql, ' ) a;');

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

(我稍微编辑了您的问题,因为您对表 x 有两个不同的定义)

【讨论】:

  • 不需要在表名周围加引号。 CONCAT('SELECT * FROM ', table_name, ' WHERE ', condition) 应该是 CONCAT('SELECT * FROM ', table_name, 'WHERE ', condition)
  • @HassanVoyeau 使用示例数据(x,t 和 w),是的。但是,我们不知道实际的表名是什么,这个方法可能会被部署到哪里,所以反引号是经过深思熟虑的。阅读dev.mysql.com/doc/refman/5.6/en/identifiers.html
  • 哦。不知道更好。同意。
猜你喜欢
  • 1970-01-01
  • 2016-12-22
  • 2013-09-19
  • 2022-08-09
  • 2016-09-06
  • 2011-08-12
  • 2014-05-15
  • 1970-01-01
  • 2015-08-03
相关资源
最近更新 更多