我正在编写一个C#WinForms程序,其中包括一个用户输入文本框,该文本框的值将用于创建表。我一直在思考处理无效T-SQL表名称的最佳方法是什么(尽管可以将其扩展到许多其他情况)。目前,我能想到的唯一方法是单独检查输入字符串中是否存在违反有效表名的行为,尽管这似乎很麻烦,并且由于我自己对违规行为的无知和例如可能会丢失某些字符。不是。
我觉得应该有一个更好的方法,但是到目前为止,我一直找不到任何东西。谁能帮助我指出正确的方向?
答案 0 :(得分:2)
正如已经在评论中告诉您的那样,您不应该这样做...
您可能会使用类似的东西
USE master;
GO
CREATE DATABASE dbTest;
GO
USE dbTest;
GO
CREATE TABLE UserTables(ID INT IDENTITY CONSTRAINT PK_UserTables PRIMARY KEY
,UserInput NVARCHAR(500) NOT NULL CONSTRAINT UQ_UserInput UNIQUE);
GO
INSERT INTO UserTables VALUES(N'blah')
,(N'invalid !%$& <<& >< $')
,(N'silly ');
GO
SELECT * FROM UserTables;
/*
ID UserInput
1 blah
2 invalid !%$& <<& >< $
3 silly
*/
GO
USE master;
GO
DROP DATABASE dbTest;
GO
然后将您的表创建为Table1
,Table2
,依此类推。
每当用户输入字符串时,您就访问表,选择ID并通过将单词Table
与ID
串联来创建表的名称。
但是您应该考虑一个修复方案。您将必须定义列(多少列,哪种类型,如何命名?)。当您不得不查询时,您会感到地狱。不用依赖...
一种方法是经典的n:m
映射
根据需要,您可以添加一个表
然后使用映射将问题绑定到测试,并使用另一个映射将答案绑定到此类映射的问题。
另一种方法是将结果存储为通用容器(XML或JSON)。这样可以使表保持苗条,但是需要知道XML的结构才能查询它。
有很多方法可以给兔子剥皮...
您要求解释...
关系数据库的主要优点是众所周知的结构。
预编译查询,缓存结果,统计信息,索引已知结构的需求。
通过约束,外键等确保数据完整性。所有这些都需要已知的名称,已知的类型(!)和已知的关系。
特定于用户的表名,甚至更糟:通用定义的结构,不允许任何连接或其他典型的RDBMS操作。唯一的方法是动态创建每个语句(字符串构建)
经验法则是:每当您认为必须为相同的对象创建多个但名称不同的对象时,就应该考虑设计。存储Phone1
,Phone2
和Phone3
是不好的。最好有一个带有用户ID和Phone
列(经典1:n
)的边表。拥有SalesCustomerA
,SalesCustomerB
,更好地使用Customer
表并将其ID绑定为FK作为通用Sales
表是很不好的。
你明白我的意思吗?属于一起的东西应该放在一个表中。如果需要分隔,请在表中添加列,并将其用于分组和过滤。
假设您想对所有用户测试表进行一些统计评估。如果您不能共同依靠某种结构,您将如何将数据收集到一个大池中?
我希望这可以清楚...
如果您仍然坚持自己的想法,那么应该尝试一下我的代码示例。这样可以将任何愚蠢的字符串映射到安全且易于处理的表名。
答案 1 :(得分:0)
许多用户输入表名可能会出错。一堆乱七八糟的名字是维护的噩梦。用户甚至都不应该知道表名。由于现在该程序必须具有数据库所有者权限,因此存在安全风险。您想将用户限制为最低权限。
类似于Shnugo,但具有复合主键。这样可以防止重复的用户ID,testID。
user
ID int identity PK
varchar(100) fName
varchar(100) lName
test
ID int identity PK
varchar(100) name
userTest
int userID PK FK to User
int testID PK FK to Test
int score
select t.Name, u.Name, ut.score
from userTest ut
join Test t
on t.ID = ut.testID
join User u
on u.ID = ut.userID
order by t.Name, u.Name