如何在typeorm中合并两个表?

问题描述 投票:0回答:4

我想在 typeorm 中合并两个表。

第一个版本: 我为每个表创建了 sql 原始查询

    const tableUn = this.tableUnion.createQueryBuilder('tu')
        .select('id')
        .addSelect('description', 'name')
        .getQuery();

    const tableTg = this.tags.createQueryBuilder('tg')
        .select(['id', 'name'])
        .getQuery();

使用 union 创建 slq 原始查询后:

const tags = await entityManager.query(`${ tableUn } UNION ${ tableTg }`);

创建新实体并向其插入收到的数据。

const createdEntity = entityManager.create(TableUnion, tags);

最后,我想在连接查询生成器中使用这个实体,但它不起作用

      const result = await connection.createQueryBuilder()
          .from(createdEntity, 'cE')
          .getRawMany();

第二版:

    const a = connection
        .createQueryBuilder()
        .select('*')
        .from(qb => qb
            .from(TableUnion, 'tu')
            .select('id')
            .addSelect('description', 'tu.name'),
            'ttu'
        )
        .addFrom(qb => qb
            .from(TagsEntity, 'tg')
            .select('id')
            .addSelect('tg.name'),
            'ttg'
        )

它创建了包含两个表中的数据和列的表,但未连接

nestjs typeorm
4个回答
4
投票

我自己找到了这个解决方案。

// two queries with different parameters from the same table
const query1WithParams = repo.createQueryBuilder("table1")
.select("table1.id")
.where("table1.id = :input_id" , { input_id : 5 })
.getQueryAndParameters();

const query2WithParams = repo.createQueryBuilder("table1")
.select("table1.id")
.where("table1.id = :input_id" , { input_id : 10 })
.getQueryAndParameters();

请记住,如果您没有任何参数,最好使用

.getQuery()
而不是
.getQueryAndParameters()
。 那么让我解释一下您可能会遇到的问题。 如果您没有参数,一切都很好,您无需任何准备即可使用查询。但如果您有像我在顶部的示例一样的参数,您必须自己更改参数占位符以避免它们发生冲突。

如果您查看这两个查询的结果,您会发现它们都有确切的

WHERE
子句

-- Result of query1WithParams and the parameter must be 5
WHERE "table1"."id" > $1

-- Result of query2WithParams and the parameter must be 10
WHERE "table1"."id" > $1 

如您所见,我们有一个占位符代表两个值 (

5
,),但它不起作用,因此我们必须将其中之一更改为
$2
(不同的数据库有自己的参数格式,这个例子是关于
Postgres
的。如果你想了解更多,请看这个问题。) 您可以像这样更改其中之一:

const [query2, params2] = query2WithParams
const correct_query2 = query.replace("$1", "$2")

之后,您必须将参数数组合并为一个(它们的顺序很重要)

const [query1, params1] = query1WithParams
const correct_params = [...params1, ...params2]

现在您可以使用它们作为联合的输入查询。

const result = await repo.manager.query(
"(" + query1 +")" + "UNION" + "(" + correct_query2 +")",
correct_params
)

2
投票

我发现在查询构建器中处理联合的最佳方法是构建您自己的 UNION SQL 字符串,其中包含来自其他查询构建器的查询,然后在新查询构建器的 FROM 子查询 中使用它。

在给定一组查询构建器的情况下,这是一种实现此目的的方法

// Assume we have an array of query builders that all select column1 and column2
const queryBuilders: SelectQueryBuilder<unknown>[]

const sqlQueries = queryBuilders.map((b) => b.getQuery());

// Merge all the parameters from the other queries into a single object. You'll need to make sure that all your parameters have unique names
const sqlParameters = queryBuilders
  .map((b) => b.getParameters())
  .reduce((prev, curr) => ({ ...prev, ...curr }), {});

// Join all your queries into a single SQL string
const unionedQuery = '(' + sqlQueries.join(') UNION (') + ')';

// Create a new querybuilder with the joined SQL string as a FROM subquery
const unionQueryBuilder: SelectQueryBuilder<unknown> = dataSource
  .createQueryBuilder()
  .select('column1, column2')
  .from(`(${unionedQuery})`, 'combined_queries_alias')
  .setParameters(sqlParameters);

此解决方案似乎不会遇到此答案中描述的参数冲突问题。我相信这是因为当您在查询构建器中使用组合 SQL 时,TypeORM 会负责重新编号参数,但当您直接在查询中使用它时,它不会。


0
投票

您可以使用公用表表达式来实现这一点。 addCommonTableExpression() 方法接受一个字符串,您可以在其中放置 UNION 查询。


-4
投票

我认为你可以执行以下操作:

   const tableUn = this.tableUnion.createQueryBuilder('tu')
  .select('id')
  .addSelect('description', 'name')
  .getRawMany();
    
  const tableTg = this.tags.createQueryBuilder('tg')
  .select(['id', 'name'])
  .getRawMany();

   return tableUn.concat(tableTg)
© www.soinside.com 2019 - 2024. All rights reserved.