MS SQL 服务器:在准备好的语句中访问本地临时 table
MS SQL Server: Access a local temporary table in a prepared statement
问题陈述
我正在尝试创建并填充一个本地临时 table,它现在运行良好,但之后我无法通过 pepared 查询访问 table 及其内容。
问题的一个非常简化的版本,它已经重现了问题(C++0x with Qt5 framework):
// fyi: this constructor overload already executes the given query string
QSqlQuery query1("IF EXISTS(SELECT * FROM SYSOBJECTS WHERE ID=OBJECT_ID('#tmp') AND XTYPE='U') DROP TABLE #tmp", _db);
QSqlQuery query2("SELECT * INTO #tmp FROM mytable WHERE 1 = 0", _db);
// so far, so good: the table gets dropped if it was already existing and gets recreated with the schema of 'mytable'; it is empty due to the '1 = 0'
// this works: some code for inserting data
QSqlQuery query3("INSERT INTO #tmp SELECT mytable WHERE ...", _db);
// this also works: i can select some data
QSqlQuery query4("SELECT count(*) FROM #tmp WHERE col = 1234", _db);
Q_ASSERT(query4.hasNext());
// fails at exec() with error: "unkown object name '#tmp'"
QSqlQuery query5(_db);
query5.prepare("SELECT count(*) FROM #tmp WHERE col = :boundVar");
query5.bindValue(":boundVar", 1234);
query5.exec();
我在这里想念什么?我已经很难获得创建临时 table 到 运行 的查询,直到我在 SQL Server documentation:
中读到这个
In SQL Server 2005, the prepared statements cannot be used to create
temporary objects [...], such as temporary tables. These procedures
must be executed directly.
这已经很令人困惑了,因为我使用的是 SQL Server 2008r2 - 而为 Server 2012 编写的文档只提到了 2005 版本和更早版本。尽管如此,我尝试在没有准备的情况下执行创建 table 的查询并且它有效(参见代码示例)。然而,引述并没有说明通过准备好的语句访问临时table。
要求
由于性能原因,我必须使用本地临时文件 table:相当大的数据集将被过滤和转换并插入临时文件 table,其中大约有 10 个查询将跟随并使用这个具体化的中间数据。 TVP 不是一个好的选择,因为它会大大减慢以下查询的速度。在我的案例中,创建临时 table 的开销确实得到了好几次回报。此外,本地临时 table 比其他解决方案更受欢迎,因为它们与其他连接隔离并且在断开连接后将被清理,这正是我想要的。
有很多原因导致我不能没有阅读 table 的准备好的陈述,所以我真的希望有人能帮助我。
真题
如何使用准备好的查询从我的本地临时 table(当然是从创建它的同一连接中)读取数据?
非常感谢 idea/solution!
如何将所有这些都放在一个存储过程中,存储过程会创建一个真正的 table,前缀为日期和时间,以及用户 ID。
大致如此
创建TABLEsomeuser_190320151830.....
如上所述构建动态 sql 语句以填充 table
SELECT 来自 table 的任何内容,以便您的应用可以使用它
丢弃 TABLE someuser_190320151830
最后一步可能是 select 数据然后删除 table。
除非同一个人设法 运行 它可以在同一时间工作。我使用过类似的方法,但它很少运行。
具体解决方案
经过多次测试和实验,并根据 user1683641 and Tab Alleman 的想法,我将所有内容组合成最终可以完成工作并满足我所有要求的东西:
- 我现在正在使用全局临时表,因为它们在非准备查询和准备查询范围之间可见
- 当客户端应用程序在没有显式
DROP
的情况下关闭时,即使它被终止或连接丢失,也会清理全局临时表
- 我用唯一的 GUID 为这些表添加后缀,这样可以避免用户和时间戳组合的冲突
最小示例:
QString const tableName(QString("##tmp_%1").arg(QUuid::createUuid().toString()));
// clean up, prepare empty table and fill with intermediate data
QSqlQuery query1(QString("IF EXISTS(SELECT * FROM SYSOBJECTS WHERE ID=OBJECT_ID('%1') AND XTYPE='U') DROP TABLE %1").arg(tableName), _db);
QSqlQuery query2(QString("SELECT * INTO %1 FROM mytable WHERE 1 = 0").arg(tableName), _db);
QSqlQuery query3(QString("INSERT INTO %1 SELECT mytable WHERE ...").arg(tableName), _db);
// works now! I can now select the temporary data perfectly fine from prepared statements
QSqlQuery query4(_db);
query4.prepare(QString("SELECT count(*) FROM %1 WHERE col = :boundVar").arg(tableName));
query4.bindValue(":boundVar", 1234);
query4.exec();
感谢大家的参与!我会接受 user1683641 的回答,因为它引导我这样做。
问题陈述
我正在尝试创建并填充一个本地临时 table,它现在运行良好,但之后我无法通过 pepared 查询访问 table 及其内容。
问题的一个非常简化的版本,它已经重现了问题(C++0x with Qt5 framework):
// fyi: this constructor overload already executes the given query string
QSqlQuery query1("IF EXISTS(SELECT * FROM SYSOBJECTS WHERE ID=OBJECT_ID('#tmp') AND XTYPE='U') DROP TABLE #tmp", _db);
QSqlQuery query2("SELECT * INTO #tmp FROM mytable WHERE 1 = 0", _db);
// so far, so good: the table gets dropped if it was already existing and gets recreated with the schema of 'mytable'; it is empty due to the '1 = 0'
// this works: some code for inserting data
QSqlQuery query3("INSERT INTO #tmp SELECT mytable WHERE ...", _db);
// this also works: i can select some data
QSqlQuery query4("SELECT count(*) FROM #tmp WHERE col = 1234", _db);
Q_ASSERT(query4.hasNext());
// fails at exec() with error: "unkown object name '#tmp'"
QSqlQuery query5(_db);
query5.prepare("SELECT count(*) FROM #tmp WHERE col = :boundVar");
query5.bindValue(":boundVar", 1234);
query5.exec();
我在这里想念什么?我已经很难获得创建临时 table 到 运行 的查询,直到我在 SQL Server documentation:
中读到这个In SQL Server 2005, the prepared statements cannot be used to create temporary objects [...], such as temporary tables. These procedures must be executed directly.
这已经很令人困惑了,因为我使用的是 SQL Server 2008r2 - 而为 Server 2012 编写的文档只提到了 2005 版本和更早版本。尽管如此,我尝试在没有准备的情况下执行创建 table 的查询并且它有效(参见代码示例)。然而,引述并没有说明通过准备好的语句访问临时table。
要求
由于性能原因,我必须使用本地临时文件 table:相当大的数据集将被过滤和转换并插入临时文件 table,其中大约有 10 个查询将跟随并使用这个具体化的中间数据。 TVP 不是一个好的选择,因为它会大大减慢以下查询的速度。在我的案例中,创建临时 table 的开销确实得到了好几次回报。此外,本地临时 table 比其他解决方案更受欢迎,因为它们与其他连接隔离并且在断开连接后将被清理,这正是我想要的。
有很多原因导致我不能没有阅读 table 的准备好的陈述,所以我真的希望有人能帮助我。
真题
如何使用准备好的查询从我的本地临时 table(当然是从创建它的同一连接中)读取数据?
非常感谢 idea/solution!
如何将所有这些都放在一个存储过程中,存储过程会创建一个真正的 table,前缀为日期和时间,以及用户 ID。
大致如此
创建TABLEsomeuser_190320151830.....
如上所述构建动态 sql 语句以填充 table
SELECT 来自 table 的任何内容,以便您的应用可以使用它
丢弃 TABLE someuser_190320151830
最后一步可能是 select 数据然后删除 table。
除非同一个人设法 运行 它可以在同一时间工作。我使用过类似的方法,但它很少运行。
具体解决方案
经过多次测试和实验,并根据 user1683641 and Tab Alleman 的想法,我将所有内容组合成最终可以完成工作并满足我所有要求的东西:
- 我现在正在使用全局临时表,因为它们在非准备查询和准备查询范围之间可见
- 当客户端应用程序在没有显式
DROP
的情况下关闭时,即使它被终止或连接丢失,也会清理全局临时表 - 我用唯一的 GUID 为这些表添加后缀,这样可以避免用户和时间戳组合的冲突
最小示例:
QString const tableName(QString("##tmp_%1").arg(QUuid::createUuid().toString()));
// clean up, prepare empty table and fill with intermediate data
QSqlQuery query1(QString("IF EXISTS(SELECT * FROM SYSOBJECTS WHERE ID=OBJECT_ID('%1') AND XTYPE='U') DROP TABLE %1").arg(tableName), _db);
QSqlQuery query2(QString("SELECT * INTO %1 FROM mytable WHERE 1 = 0").arg(tableName), _db);
QSqlQuery query3(QString("INSERT INTO %1 SELECT mytable WHERE ...").arg(tableName), _db);
// works now! I can now select the temporary data perfectly fine from prepared statements
QSqlQuery query4(_db);
query4.prepare(QString("SELECT count(*) FROM %1 WHERE col = :boundVar").arg(tableName));
query4.bindValue(":boundVar", 1234);
query4.exec();
感谢大家的参与!我会接受 user1683641 的回答,因为它引导我这样做。