【发布时间】:2015-12-28 00:58:48
【问题描述】:
我正在尝试使用FOR JSON PATH 更改查询的 JSON 输出的嵌套。 FOR JSON AUTO 查询几乎是我需要的,但并不完全。
使用FOR JSON AUTO查询:
SELECT
table_name = tables.name,
table_object_id = tables.object_id,
index_name = indexes.name,
index_id = indexes.index_id,
column_name = columns.name,
column_id = index_columns.index_column_id,
max_length = columns.max_length,
precision = columns.precision,
scale = columns.scale
FROM
sys.indexes indexes
INNER JOIN
sys.index_columns index_columns ON indexes.object_id = index_columns.object_id and indexes.index_id = index_columns.index_id
INNER JOIN
sys.columns columns ON index_columns.object_id = columns.object_id and index_columns.column_id = columns.column_id
INNER JOIN
sys.tables tables ON indexes.object_id = tables.object_id
WHERE tables.name LIKE 'tbl_%'
ORDER BY
tables.name, indexes.index_id, index_columns.index_column_id
FOR JSON AUTO
使用FOR JSON AUTO查询输出(sn-p):
.
.
.
{
"table_name": "tbl_Agent",
"table_object_id": 176055713,
"indexes": [
{
"index_name": "PK_Task_tbl_Agent",
"index_id": 1,
"columns": [
{
"column_name": "PartitionId",
"max_length": 4,
"precision": 10,
"scale": 0,
"index_columns": [
{
"column_id": 1
}
]
},
{
"column_name": "AgentId",
"max_length": 4,
"precision": 10,
"scale": 0,
"index_columns": [
{
"column_id": 2
}
]
}
]
},
{
"index_name": "IX_Task_tbl_Agent_PoolId_AgentName",
"index_id": 2,
"columns": [
{
"column_name": "PartitionId",
"max_length": 4,
"precision": 10,
"scale": 0,
"index_columns": [
{
"column_id": 1
}
]
},
{
"column_name": "PoolId",
"max_length": 4,
"precision": 10,
"scale": 0,
"index_columns": [
{
"column_id": 2
}
]
},
{
"column_name": "AgentName",
"max_length": 128,
"precision": 0,
"scale": 0,
"index_columns": [
{
"column_id": 3
}
]
}
]
},
{
"index_name": "IX_Task_tbl_Agent_PoolId_SessionId",
"index_id": 3,
"columns": [
{
"column_name": "PartitionId",
"max_length": 4,
"precision": 10,
"scale": 0,
"index_columns": [
{
"column_id": 1
}
]
},
{
"column_name": "PoolId",
"max_length": 4,
"precision": 10,
"scale": 0,
"index_columns": [
{
"column_id": 2
}
]
},
{
"column_name": "SessionId",
"max_length": 16,
"precision": 0,
"scale": 0,
"index_columns": [
{
"column_id": 3
}
]
}
]
}
]
},
.
.
.
每个表的所有索引都正确嵌套,并且在每个索引中,索引的所有列(这些是复合索引)都正确嵌套。我要做的唯一更改是取消嵌套index_columns,使column_id 成为columns 的一部分,例如:
.
.
.
"columns": [
{
"column_name": "PartitionId",
"max_length": 4,
"precision": 10,
"scale": 0,
---> "column_id": 1
},
{
"column_name": "PoolId",
"max_length": 4,
"precision": 10,
"scale": 0,
---> "column_id": 2
},
{
"column_name": "AgentName",
"max_length": 128,
"precision": 0,
"scale": 0,
---> "column_id": 3
}
]
.
.
.
但是,当我尝试使用 FOR JSON PATH 时,它最终嵌套不正确。
使用FOR JSON PATH查询:
SELECT
tables.name AS [tables.table_name],
tables.object_id AS [tables.table_object_id],
indexes.name AS [tables.indexes.index_name],
indexes.index_id AS [tables.indexes.index_id],
columns.name AS [tables.indexes.columns.column_name],
index_columns.index_column_id AS [tables.indexes.columns.column_id],
columns.max_length AS [tables.indexes.columns.max_length],
columns.precision AS [tables.indexes.columns.precision],
columns.scale AS [tables.indexes.columns.scale]
FROM
sys.indexes indexes
INNER JOIN
sys.index_columns index_columns ON indexes.object_id = index_columns.object_id and indexes.index_id = index_columns.index_id
INNER JOIN
sys.columns columns ON index_columns.object_id = columns.object_id and index_columns.column_id = columns.column_id
INNER JOIN
sys.tables tables ON indexes.object_id = tables.object_id
WHERE tables.name LIKE 'tbl_%'
ORDER BY
tables.name, indexes.index_id, index_columns.index_column_id
FOR JSON PATH
使用FOR JSON PATH查询输出(sn-p):
.
.
.
{
"tables": {
===> "table_name": "tbl_Agent",
"table_object_id": 176055713,
"indexes": {
---> "index_name": "PK_Task_tbl_Agent",
"index_id": 1,
"columns": {
"column_name": "PartitionId",
"column_id": 1,
"max_length": 4,
"precision": 10,
"scale": 0
}
}
}
},
{
"tables": {
===> "table_name": "tbl_Agent",
"table_object_id": 176055713,
"indexes": {
---> "index_name": "PK_Task_tbl_Agent",
"index_id": 1,
"columns": {
"column_name": "AgentId",
"column_id": 2,
"max_length": 4,
"precision": 10,
"scale": 0
}
}
}
},
{
"tables": {
===> "table_name": "tbl_Agent",
"table_object_id": 176055713,
"indexes": {
"index_name": "IX_Task_tbl_Agent_PoolId_AgentName",
"index_id": 2,
"columns": {
"column_name": "PartitionId",
"column_id": 1,
"max_length": 4,
"precision": 10,
"scale": 0
}
}
}
},
.
.
.
虽然column_id 现在是我想要的位置,但columns 现在是唯一正确嵌套的东西。每个table 现在对其每个indexes 重复,每个index 对其每个columns 重复。
如何在我想要的位置获得column_id(如FOR JSON PATH 查询的输出),同时保持正确的嵌套(如FOR JSON AUTO 查询的输出)?
更新 -- 工作中
根据 DimaSUN 的回复和 Ben 的评论,我想出了这个正在运行的查询:
SELECT
tables.name AS [table_name],
tables.object_id AS [table_object_id],
(SELECT
indexes.name AS [index_name],
indexes.index_id AS [index_id],
(SELECT
columns.name AS [column_name],
index_columns.index_column_id AS [column_id],
columns.max_length AS [max_length],
columns.precision AS [precision],
columns.scale AS [scale]
FROM
sys.index_columns index_columns
JOIN
sys.columns columns ON index_columns.object_id = columns.object_id and index_columns.column_id = columns.column_id
WHERE
indexes.object_id = index_columns.object_id and indexes.index_id = index_columns.index_id
ORDER BY
index_columns.index_column_id
FOR JSON PATH
) AS 'columns'
FROM
sys.indexes indexes
WHERE
indexes.object_id = tables.object_id
ORDER BY
indexes.index_id
FOR JSON PATH
) AS 'indexes'
FROM
sys.tables tables
WHERE
tables.name LIKE 'tbl_%'
ORDER BY
tables.name
FOR JSON PATH, ROOT('tables')
新查询输出(sn-p):
.
.
.
{
"table_name": "tbl_Agent",
"table_object_id": 176055713,
"indexes": [
{
"index_name": "PK_Task_tbl_Agent",
"index_id": 1,
"columns": [
{
"column_name": "PartitionId",
"column_id": 1,
"max_length": 4,
"precision": 10,
"scale": 0
},
{
"column_name": "AgentId",
"column_id": 2,
"max_length": 4,
"precision": 10,
"scale": 0
}
]
},
{
"index_name": "IX_Task_tbl_Agent_PoolId_AgentName",
"index_id": 2,
"columns": [
{
"column_name": "PartitionId",
"column_id": 1,
"max_length": 4,
"precision": 10,
"scale": 0
},
{
"column_name": "PoolId",
"column_id": 2,
"max_length": 4,
"precision": 10,
"scale": 0
},
{
"column_name": "AgentName",
"column_id": 3,
"max_length": 128,
"precision": 0,
"scale": 0
}
]
},
{
"index_name": "IX_Task_tbl_Agent_PoolId_SessionId",
"index_id": 3,
"columns": [
{
"column_name": "PartitionId",
"column_id": 1,
"max_length": 4,
"precision": 10,
"scale": 0
},
{
"column_name": "PoolId",
"column_id": 2,
"max_length": 4,
"precision": 10,
"scale": 0
},
{
"column_name": "SessionId",
"column_id": 3,
"max_length": 16,
"precision": 0,
"scale": 0
}
]
}
]
},
.
.
.
嵌套选择末尾的 AS 'columns' 和 AS 'indexes' 是一个关键部分,否则我会收到以下错误:
Msg 13605, Level 16, State 1, Line 1
Unnamed tables cannot be used as JSON identifiers as well as unnamed columns cannot be used as key names. Add alias to the unnamed column/table.
【问题讨论】:
-
您通常希望为此类事情执行相关子查询。也就是说,您的驾驶查询将是
select * from sys.tables as twhere name like 'tbl_%',而不是选择“*”,您将发出一个选择,例如,sys.indexes 看起来像select i.name from sys.indexes as i where i.object_id = t.object_id。 where 子句说“给我正在考虑的当前表的索引”。 -
感谢您的回复,本!帮助很大。请参阅上面的更新。
-
@BenThul 那么这意味着对于上述场景我们除了使用子查询之外别无选择使用内连接?
-
内部连接的问题是每次匹配都会产生一行。例如,假设您有一个关系,其中 tableA 中的每一行在 tableB 中有 10 行。如果 tableA 有 5 行,而您执行
select * from tableA join tableB,您将返回 5x10=50 行。您可以将其转换为 JSON,但大多数情况下,您会希望 JSON 具有(在我的示例中)5 个元素,每个元素有 10 个属性。
标签: sql-server json nested sql-server-2016