我将要建立一个由DotNetNuke(目前是我最喜欢的CMS,主要是因为它是免费的)支持的新网站,并且我想在同一台计算机上安装Counter-Strike游戏服务器。 我还想要一个小模块,它将向我的站点的访问者显示多少人登录到CS服务器以及一些基本统计信息。
听起来很简单吧?
问题在于,当安装Counter-Strike服务器时,数据库名称是随机生成的。 所以我无法创建指向数据源的连接字符串,因为我不知道初始目录。 但是,我确实知道CS表是什么样子。
在SQL Server中,无法仅通过运行一个查询来获取所有数据库中的所有表名。 因此,我创建了一些代码:
- 获取服务器上的所有数据库;
- 查询INFORMATION_SCHEMA.tables表,该表保存数据库中所有表的名称;
- 返回包含CS表的数据库的名称(在本例中为cs_server)。
下面的代码就是使用动态SQL来完成的-可以这么说的SQL。
事不宜迟,这里是代码:
CREATE PROCEDURE GetCounterStrikeServerDetails AS
BEGIN
CREATE TABLE #tmp (
tmpdbname nvarchar(MAX)
)
DECLARE @useronline nvarchar(MAX)
DECLARE @dbname nvarchar(255)
DECLARE @csdb nvarchar(255)
DECLARE @sql nvarchar(MAX)
DECLARE dbcur CURSOR FOR
(SELECT name FROM sys.databases)
OPEN dbcur
FETCH NEXT FROM dbcur INTO @dbname
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sql = 'IF (SELECT COUNT(*) FROM ' + @dbname + '.INFORMATION_SCHEMA.tables WHERE TABLE_NAME = ''cs_servers'') = 1 INSERT INTO #tmp SELECT ''' + @dbname + ''''
EXEC(@sql)
FETCH NEXT FROM dbcur INTO @dbname
END
CLOSE dbcur
DEALLOCATE dbcur
SET @csdb = CONVERT(nvarchar(max), (SELECT tmpdbname FROM #tmp))
DROP TABLE #tmp
SET @useronline = 'SELECT name, cur_players, cur_map, maxplayers FROM ' + @csdb + '.dbo.cs_servers '
SET @useronline = @useronline + 'INNER JOIN ' + @csdb + '.dbo.cs_params ON ' + @csdb + '.dbo.cs_params.server_id = ' + @csdb + '.dbo.cs_servers.id'
EXEC(@useronline)
END
让我们来看一下这段代码。
首先,我声明了一个临时表(3-5行)。 原因是因为在尝试获取数据库名称(第16行)时,我在变量范围方面遇到了麻烦。
其次,声明一些变量来保存我将要使用的数据(第6-9行)-@useronline和@sql来保存我动态生成的SQL代码,@ dbname来让我的游标遍历每个数据库,当我发现它时,使用@csdb表示实际的Counter-Strike数据库的名称。
第三,打开一个游标,该游标遍历sys.databases中列出的每个数据库(第10-14行)。
第16行是关键。 对于每个数据库,如果我在INFORMATION_SCHEMA.tables中找到一个与我要访问的表的名称(cs_server)相匹配的条目,我想在临时表中插入一个带有数据库名称的行。
第20和21行是游标的垃圾回收。
第22和23行仅获取CS数据库的名称并将其放入变量中,然后删除temp表(垃圾收集)。
第24和25行使用CS数据库名称和CS数据库结构的已知表名称来构建SELECT JOIN语句。
第26行执行上述SELECT JOIN语句,该语句为您提供服务器名称,允许的最大用户数,当前映射以及当前已连接并正在播放的用户数。
如果删除第24-26行,则此代码可适用于多种用途-例如,在软件资产管理方案中,该代码可用于查找安装在数据库服务器上的特定软件。
医务工作者
From: https://bytes.com/topic/sql-server/insights/841123-dynamic-sql-quick-tutorial