SQL 视图中的双列
Posted
技术标签:
【中文标题】SQL 视图中的双列【英文标题】:Double columns in a SQL View 【发布时间】:2011-05-24 09:39:17 【问题描述】:我们有一个旧接口插入到表 T1 中,其值为 "BODY_TEXT" (varcharmax)
、"BODY_BIN"(varbinarymax)
。
它当前只插入其中一列,而将另一列保留为 NULL。
现在我们实现了一个新接口——表 T2,它只有 "BODY"(varbinarymax)
列。
我需要创建一个视图 V1 来代替 T1,意思是
CREATE VIEW V1 AS
SELECT
T2.UNIQUE_ID AS UNIQUE_ID,
等等……
现在我不知道如何处理T2.BODY
列……我需要做类似的事情
T2.BODY AS (whatever is not null(BODY_BIN, BODY_TEXT))
。它还必须支持 varcharmax
与 varbinarymax。
我尝试实现COALESCE
,意思是T2.BODY AS COALESCE(BODY_BIN, BODY_TEXT)
,但它不起作用。
也没有
COALESCE(BODY_BIN, BODY_TEXT) AS BODY
T2.BODY AS BODY
再次 - 在旧表中,我们的 T1 有两列 - BODY_BIN 和 BODY_TEXT。用户插入了一个值,而将另一个留空,因为 body 要么是二进制的,要么是文本的,但不是两者兼而有之。新界面有一个表 T2,它只有一列 BODY (varbinarymax),我被要求删除表 T1 并创建一个同名的视图。意思是为了保持向后可比性,他们应该仍然能够执行“插入 T1 值 X,Y”(X 是 DATA_BIN 或 NULL,Y 是 DATA_TEXT 或 NULL),但内容(取自 X 或 Y)应该被翻译成 T2 表中的一列 - BODY。 我不知道如何把这个拉起来。
你能帮帮我吗?
谢谢,
尼莉
【问题讨论】:
我不确定我是否理解。 COALESCE(varbinary 到 varchar(注意顺序)将隐式转换。所以这是可行的,因为 ISNULL 采用第一个数据类型
ISNULL(varchar, varbinary)
COALESCE 失败,因为它采用最高优先级数据类型(即 varbinary)。不允许隐式转换。 ISNULL(varbinary, varchar)
也会失败
你需要一个明确的 CAST
DECLARE @foo TABLE (ID int IDENTITY (1,1), charmax varchar(MAX) NULL, binmax varbinary(MAX) NULL)
INSERT @foo (charmax, binmax) VALUES ('text', NULL)
INSERT @foo (charmax, binmax) VALUES (NULL, 0x303131)
INSERT @foo (charmax, binmax) VALUES ('Moretext', NULL)
INSERT @foo (charmax, binmax) VALUES (NULL, 0x414243454647)
SELECT ISNULL(binmax, CONVERT(varbinary(MAX), charmax))
FROM @foo
或
SELECT COALESCE(binmax, CONVERT(varbinary(MAX), charmax))
FROM @foo
编辑:我现在明白了这个问题......也许
DECLARE @foo2 TABLE (ID int IDENTITY (1,1), BODY varbinary(MAX) NULL)
INSERT @foo2 (BODY) VALUES (CAST('text' AS varbinary(MAX)))
INSERT @foo2 (BODY) VALUES (0x303132)
INSERT @foo2 (BODY) VALUES (CAST('Moretext' AS varbinary(MAX)))
INSERT @foo2 (BODY) VALUES (0x414243454647)
SELECT
BODY AS BODY_BIN,
CAST(BODY AS varchar(MAX)) AS BOY_TEXT
FROM
@foo2
Edit2:类似这样的东西(未测试)保持相同的写入接口。通常,我只会维护一个读取接口,因此会造成混乱......
CREATE VIEW OldFoo
AS
SELECT
ID,
BODY AS BODY_BIN,
CAST(BODY AS varchar(MAX)) AS BOY_TEXT
FROM
newFoo
GO
CREATE TRIGGER ON OldFoo INSTEAD OF INSERT
AS
SET NOCOUNT ON
INSERT newFoo (BODY)
SELECT ISNULL(binmax, CONVERT(varbinary(MAX), charmax))
FROM INSERTED
GO
【讨论】:
我仍然不知道一个简单的演员表是否可行,我仍然落后了一步,因为我不知道如何将表 T2 中的一个“物理”列绑定到非 null-来自 V1 的两列中的值... @Nili:我已经给你证明它确实在我上面的脚本中工作 @gbn,仍然不完全是我的目标......我曾经有一个旧表 - DECLARE @foo TABLE (ID int IDENTITY (1,1), BODY_BIN varbinary(MAX) NULL, BODY_TEXT varchar(max)),现在我得到了一个新表 - foo2 - 就像你展示的一样。现在我的要求是删除表 foo,而是创建一个名为 foo 的视图。它应该支持老用户,这意味着支持插入 DATA_BIN 和 DATA_TEXT,但“幕后”将 JUST ONE VALUE 复制到全新的表 foo2...这是更好的解释吗? @Nili - 如果您想使用视图来查看INSERT
新数据,那么您需要有两个不同的字段,一个用于每种数据类型。另一种方法是有一个函数来执行一些逻辑来确定数据类型,但是将这种新方法塞进旧框架中的复杂程度近乎荒谬。
@Nili:所以用户仍然会尝试写入“foo”?【参考方案2】:
首先,这是一个糟糕的设计。加入varchar(max)
或varbinary(max)
字段是个坏主意,因为它们无法被索引。准备表扫描!
同一列的数据类型不一致,这是个问题。
试试:
CAST((COALESCE(BODY_BIN, BODY_TEXT)) as varchar(max))
【讨论】:
但我需要将 T2 值映射到非空值,这意味着我需要类似:T2.Body AS CAST((COALESCE(BODY_BIN, BODY_TEXT)) as varchar(max)),但是它不起作用...... @Nili:COALESCE(CAST(BODY_BIN AS varchar(max)), BODY_TEXT))
?以上是关于SQL 视图中的双列的主要内容,如果未能解决你的问题,请参考以下文章