diff --git a/frontend/src/components/QueryEditor.results-and-drop.test.tsx b/frontend/src/components/QueryEditor.results-and-drop.test.tsx
index e7fb12e..3e9ee7f 100644
--- a/frontend/src/components/QueryEditor.results-and-drop.test.tsx
+++ b/frontend/src/components/QueryEditor.results-and-drop.test.tsx
@@ -843,6 +843,43 @@ describe('QueryEditor external SQL save', () => {
expect(dataGridState.latestProps?.columnNames).toEqual(['name']);
});
+ it('hides redundant sqlserver affected-row status result after a query result', async () => {
+ storeState.connections[0].config.type = 'sqlserver';
+ storeState.connections[0].config.database = 'hydee';
+ backendApp.DBQueryMulti.mockResolvedValueOnce({
+ success: true,
+ data: [
+ {
+ statementIndex: 1,
+ columns: ['dddwno', 'dddwlist'],
+ rows: [{ dddwno: '001', dddwlist: 'demo' }],
+ },
+ { statementIndex: 1, columns: ['affectedRows'], rows: [{ affectedRows: 846 }] },
+ ],
+ });
+
+ let renderer!: ReactTestRenderer;
+ await act(async () => {
+ renderer = create();
+ });
+
+ await act(async () => {
+ await findButton(renderer!, '运行').props.onClick();
+ });
+ await act(async () => {
+ await Promise.resolve();
+ await Promise.resolve();
+ });
+
+ const rendered = textContent(renderer!.toJSON());
+ expect(rendered).toContain('结果 1');
+ expect(rendered).not.toContain('结果 2');
+ expect(rendered).not.toContain('影响行数:846');
+ expect(dataGridState.latestProps?.columnNames).toEqual(['dddwno', 'dddwlist']);
+ expect(dataGridState.latestProps?.data?.[0]).toMatchObject({ dddwno: '001', dddwlist: 'demo' });
+ expect(messageApi.success).toHaveBeenCalledWith('已执行完成,生成 1 个结果集。');
+ });
+
it('prefers the first displayable sqlserver procedure result when empty result sets are returned', async () => {
storeState.connections[0].config.type = 'sqlserver';
storeState.connections[0].config.database = 'hydee';
@@ -953,7 +990,7 @@ describe('QueryEditor external SQL save', () => {
await Promise.resolve();
});
- expect(textContent(renderer!.toJSON())).toContain('消息 2');
+ expect(textContent(renderer!.toJSON())).toContain('消息 1');
expect(findResultMessageTextarea(renderer!).props.value).toBe([
"insert into c_dyscript(projectid,name) values (1,'demo')",
"insert into c_dyscript(projectid,name) values (2,'next')",
@@ -1033,7 +1070,7 @@ describe('QueryEditor external SQL save', () => {
await Promise.resolve();
});
- expect(textContent(renderer!.toJSON())).toContain('消息 2');
+ expect(textContent(renderer!.toJSON())).toContain('消息 1');
expect(findResultMessageTextarea(renderer!).props.value).toBe("insert into c_dyscript(projectid,name) values (1,'demo')");
expect(textContent(renderer!.toJSON())).not.toContain('影响行数:0');
expect(dataGridState.latestProps).toBeNull();
diff --git a/frontend/src/components/QueryEditor.tsx b/frontend/src/components/QueryEditor.tsx
index 6be259e..0d4af9d 100644
--- a/frontend/src/components/QueryEditor.tsx
+++ b/frontend/src/components/QueryEditor.tsx
@@ -2777,6 +2777,24 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
result.columns[0] === 'affectedRows',
);
+ const isAffectedRowsResultSetData = (result?: any): boolean =>
+ Boolean(
+ result &&
+ Array.isArray(result.rows) &&
+ result.rows.length === 1 &&
+ Array.isArray(result.columns) &&
+ result.columns.length === 1 &&
+ result.columns[0] === 'affectedRows',
+ );
+
+ const hasConcreteQueryResultSetData = (result: any, messages: string[]): boolean => {
+ if (!result || isAffectedRowsResultSetData(result)) return false;
+ if (messages.length > 0) return true;
+ if (Array.isArray(result.columns) && result.columns.length > 0) return true;
+ if (Array.isArray(result.rows) && result.rows.length > 0) return true;
+ return false;
+ };
+
const isMessageLikeResultSet = (result?: ResultSet | null): boolean =>
Boolean(
result &&
@@ -3492,28 +3510,49 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
const maxRows = Number(queryOptions?.maxRows) || 0;
let anyTruncated = false;
const statementResultCounts = new Map();
+ const sqlServerStatementsWithConcreteResults = new Set();
+ if (normalizedDbType === 'sqlserver') {
+ resultSetDataArray.forEach((rsData, idx) => {
+ const sourceStatementIndex = Number(rsData?.statementIndex || idx + 1);
+ const resultMessages = normalizeQueryResultMessages(rsData?.messages);
+ if (hasConcreteQueryResultSetData(rsData, resultMessages)) {
+ sqlServerStatementsWithConcreteResults.add(sourceStatementIndex);
+ }
+ });
+ }
+ const shouldUseTopLevelSqlServerMessages = normalizedDbType === 'sqlserver'
+ && topLevelMessages.length > 0
+ && sqlServerStatementsWithConcreteResults.size === 0;
for (let idx = 0; idx < resultSetDataArray.length; idx++) {
const rsData = resultSetDataArray[idx];
const sourceStatementIndex = Number(rsData?.statementIndex || idx + 1);
- const statementResultIndex = (statementResultCounts.get(sourceStatementIndex) || 0) + 1;
- statementResultCounts.set(sourceStatementIndex, statementResultIndex);
const plan = executablePlans[Math.max(0, sourceStatementIndex - 1)];
const originalSql = plan?.originalSql || '';
const executedSql = plan?.executedSql || originalSql;
const resultMessages = normalizeQueryResultMessages(rsData?.messages);
// 检查是否为 affectedRows 类结果集
- const isAffectedResult = Array.isArray(rsData.rows) && rsData.rows.length === 1
- && rsData.columns && rsData.columns.length === 1
- && rsData.columns[0] === 'affectedRows';
+ const isAffectedResult = isAffectedRowsResultSetData(rsData);
+ const shouldHideSqlServerAffectedResult = normalizedDbType === 'sqlserver'
+ && isAffectedResult
+ && (
+ sqlServerStatementsWithConcreteResults.has(sourceStatementIndex)
+ || shouldUseTopLevelSqlServerMessages
+ );
+ if (shouldHideSqlServerAffectedResult) {
+ continue;
+ }
+
+ const statementResultIndex = (statementResultCounts.get(sourceStatementIndex) || 0) + 1;
+ statementResultCounts.set(sourceStatementIndex, statementResultIndex);
if (isAffectedResult) {
const affected = Number(rsData.rows[0]?.affectedRows);
const row = { affectedRows: Number.isFinite(affected) ? affected : 0 };
(row as any)[GONAVI_ROW_KEY] = 0;
nextResultSets.push({
- key: `result-${idx + 1}`,
+ key: `result-${nextResultSets.length + 1}`,
sql: executedSql,
exportSql: originalSql,
sourceStatementIndex,
@@ -3526,7 +3565,7 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
});
} else if ((!Array.isArray(rsData.rows) || rsData.rows.length === 0) && (!Array.isArray(rsData.columns) || rsData.columns.length === 0) && resultMessages.length > 0) {
nextResultSets.push({
- key: `result-${idx + 1}`,
+ key: `result-${nextResultSets.length + 1}`,
sql: executedSql,
exportSql: originalSql,
sourceStatementIndex,
@@ -3566,7 +3605,7 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
fallbackPageSize: maxRows,
});
nextResultSets.push({
- key: `result-${idx + 1}`,
+ key: `result-${nextResultSets.length + 1}`,
sql: executedSql,
exportSql: originalSql,
sourceStatementIndex,