【问题标题】:Output only certain values from nvarchar column using select statement使用 select 语句仅从 nvarchar 列输出某些值
【发布时间】:2025-12-27 03:10:11
【问题描述】:

我有一个 SQL 数据库,其中包含各种日志信息,包括 Windows 事件日志的完整描述。此描述是一个 nvarchar 列,其中包含如下所示的信息:

An account failed to log on.

Subject:
    Security ID:        S-1-5-18
    Account Name:       XXX-XXX01$
    Account Domain:     XXX
    Logon ID:       0x3E7

Logon Type:         8

Account For Which Logon Failed:
    Security ID:        S-1-0-0
    Account Name:       username
    Account Domain:     domain

Failure Information:
    Failure Reason:     Unknown user name or bad password.
    Status:         0xC000006D
    Sub Status:     0xC0000064

Process Information:
    Caller Process ID:  0x1111
    Caller Process Name:    C:\Windows\System32\inetsrv\w3wp.exe

Network Information:
    Workstation Name:   XXX-XXX04
    Source Network Address: XXX.XXX.XXX.XXX

我只想使用 select 语句在“登录失败的帐户:”下检索“帐户名称:”和“帐户域:”之后的值,以便我可以在 Excel 和/或 Power BI 中使用它。

这可能吗?

【问题讨论】:

  • 请显示来自数据库的屏幕截图,您的数据在表格中的样子。就像字符串一样?
  • 不,不要在这里遵循@Adamszsz 的建议,文字图像永远不会有帮助。 DDL 和 DML 语句方式更好。但是如果你想消费 Windows 日志,SQL server 是完全错误的工具。肯定有一些工具可以,而且很可能其中一些工具可以将数据以 consumable 格式插入到 SQL Server 中。
  • 是的,这是可能的。正如 Larnu 所说,这绝对不是理想的方法,尤其是在您查看大量数据的情况下。但是,如果您仅在数百或数千以下的范围内消费,那并不太费力。您可能希望使用 CHARINDEX()SUBSTRING() 的组合来获得您想要的。
  • @Larnu 数据库由监控代理填充,我无法控制信息的保存位置。但是,对于某些合规性方面,我需要此信息,例如,我们需要监控失败的访问,并且此数据库是唯一具有此信息的信息存储库,并且适用于所有涉及的系统。
  • 如果它是为了合规,那么我建议这将更容易获得正确工具的预算来执行此操作。法律要求通常是公司打开钱包的最简单方法。

标签: sql sql-server select nvarchar


【解决方案1】:

我猜提供的示例是一列/一串的内容。在这种情况下,我建议使用charindexxml.nodes 的组合。

举个例子:

DECLARE @x NVARCHAR(max) = 'An account failed to log on.

Subject:
    Security ID:        S-1-5-18
    Account Name:       XXX-XXX01$
    Account Domain:     XXX
    Logon ID:       0x3E7

Logon Type:         8

Account For Which Logon Failed:
    Security ID:        S-1-0-0
    Account Name:       username
    Account Domain:     domain

Failure Information:
    Failure Reason:     Unknown user name or bad password.
    Status:         0xC000006D
    Sub Status:     0xC0000064

Process Information:
    Caller Process ID:  0x1111
    Caller Process Name:    C:\Windows\System32\inetsrv\w3wp.exe

Network Information:
    Workstation Name:   XXX-XXX04
    Source Network Address: XXX.XXX.XXX.XXX';


DECLARE @idxLogonFailed bigint = charindex('Account For Which Logon Failed:'+char(13)+char(10), @x);
DECLARE @idxFailureInfo bigint = charindex('Failure Information:'+char(13)+char(10), @x);
DECLARE @logonFailedLen int = @idxFailureInfo-@idxLogonFailed;

DECLARE @logonFailedSubstr NVARCHAR(1000) = SUBSTRING(@x, @idxLogonFailed, @logonFailedLen);
DECLARE @newLineIdx INT = charindex(char(13)+char(10), @logonFailedSubstr);

DECLARE @xXml xml = CAST(REPLACE('<a><b>' + REPLACE(@logonFailedSubstr, char(13)+char(10), '</b><b>') + '</b></a>', '<b></b>', '') AS XML);

WITH cte AS(
  SELECT TRIM(T.r.value('.', 'VARCHAR(1000)')) AS x
    FROM @xXml.nodes('/a/b') as T(r)
),
cteSplit AS(
  SELECT *, TRIM(LEFT(x, CHARINDEX(':', x)-1)) AS description, TRIM(RIGHT(x, LEN(x)-CHARINDEX(':', x))) AS val
    FROM cte
    WHERE CHARINDEX(':', x) > -1
)
SELECT description, val
  FROM cteSplit
  WHERE description IN ('Account Name','Account Domain')

【讨论】: