在MS SQL Server中以相同的键但不同的ID显示数据

huangapple go评论81阅读模式
英文:

Displaying Data In MS SQL Server With Same Key But Different ID

问题

以下是已经翻译好的部分:

让我们假设我有下面的数据:

在MS SQL Server中以相同的键但不同的ID显示数据

如何在没有使用 UNION 的情况下按最低的 ID 以及依此类推显示这些数据?

在MS SQL Server中以相同的键但不同的ID显示数据

我考虑为具有相同的 usercode 的每个数据分配序列号,为每次迭代创建临时表,然后将它们连接起来。

以下是代码:

DROP TABLE #TEMP
CREATE TABLE #TEMP (
	ID INT,
	[data] INT,
	usercode NVARCHAR(50),
	RowNum INT
)

INSERT INTO #TEMP(ID, [data], UserCode, RowNum)
SELECT Id, ApplicationID, 'john', ROW_NUMBER() OVER (ORDER BY Usercode) RNum from UserApplicationAccess

这是插入的数据,所以我为每行数据都提供了序列号,以标记具有 ID 的每个数据。

select a.UserCode, a.RowNum Id_1, a.[data] data_1, b.RowNum Id_2, b.[data] data_2 from #TEMP a join #TEMP b on a.UserCode = b.UserCode 
where a.RowNum = 1 and b.RowNum = 2 
union
select a.UserCode, a.RowNum Id_1, a.[data] data_1, b.RowNum Id_2, b.[data] data_2 from #TEMP a join #TEMP b on a.UserCode = b.UserCode 
where a.RowNum = 2 and b.RowNum = 3

这是我用来获取所需数据的查询方式,它可以工作,但由于每个用户的数据数量没有限制,我认为这个查询还不够。例如,某些用户有10个数据,所以我必须写9个联合查询,以此类推。

英文:

Let's say I have data below

在MS SQL Server中以相同的键但不同的ID显示数据

How can I display this data side by side with lowest id and so on without UNION?

在MS SQL Server中以相同的键但不同的ID显示数据

I'm thinking about giving sequence number for every data that has the same usercode, create table temporary for each iteration, and then join them.

Here the code

DROP TABLE #TEMP
CREATE TABLE #TEMP (
	ID INT,
	[data] INT,
	usercode NVARCHAR(50),
	RowNum INT
)

INSERT INTO #TEMP(ID, [data], UserCode, RowNum)
SELECT Id, ApplicationID, 'john', ROW_NUMBER() OVER (ORDER BY Usercode) RNum from UserApplicationAccess

This is inserted data, so I'm giving a sequence number for each row for mark every data with id

select a.UserCode, a.RowNum Id_1, a.[data] data_1, b.RowNum Id_2, b.[data] data_2 from #TEMP a join #TEMP b on a.UserCode = b.UserCode 
where a.RowNum = 1 and b.RowNum = 2 
union
select a.UserCode, a.RowNum Id_1, a.[data] data_1, b.RowNum Id_2, b.[data] data_2 from #TEMP a join #TEMP b on a.UserCode = b.UserCode 
where a.RowNum = 2 and b.RowNum = 3

This is how I query to get the data that I want, it works but since there is no limitation how many data for every user, I think this query is not enough. For example this data just have 3 row, so I'm using union just twice, but there are user that have 10 data, so I have to write 9 union, and so on, and so on.

答案1

得分: 1

由于你要做的是为每个用户代码获取 n-1 行,你可以使用 LEAD() 来获取下一个值,并在这个值为空时省略(即最后一行)。唯一的例外情况是如果一个用户只有一行数据,你可以通过始终包括每个用户的第一行来避免这种情况。因此,你最终会得到类似以下的结果:

WITH YourData AS
(	SELECT	ID, ApplicationID, UserCode
	FROM	(VALUES 
				(43641, 34, 'John'),(43642, 52, 'John'),(43643, 55, 'John'), (43648, 55, 'Bill'),
				(43645, 34, 'Steve'),(43646, 52, 'Steve'),(43647, 55, 'Steve'),(43648, 56, 'Steve')
			) AS d (ID, ApplicationID, UserCode)
)
SELECT	d.UserCode, 
		ID_1 = d.RowNumber, 
		Data_1 = d.ApplicationID,
		ID_2 = CASE WHEN d.NextApplicationID IS NULL THEN NULL ELSE d.RowNumber + 1 END,
		Data_2 = d.NextApplicationID
	FROM	(	SELECT	d.ID, 
					d.ApplicationID, 
					d.UserCode,
					RowNumber = ROW_NUMBER() OVER(PARTITION BY d.UserCode ORDER BY d.ApplicationID),
					NextApplicationID = LEAD(d.ApplicationID) OVER(PARTITION BY d.UserCode ORDER BY d.ApplicationID)
			FROM	YourData AS d
		) AS d
	WHERE	d.NextApplicationID IS NOT NULL
	OR		d.RowNumber = 1;

得到的结果如下:

UserCode ID_1 Data_1 ID_2 Data_2
Bill 1 55 NULL NULL
John 1 34 2 52
John 2 52 3 55
Steve 1 34 2 52
Steve 2 52 3 55
Steve 3 55 4 56

在 db<>fiddle 上的示例

英文:

Since what you are trying to do is get n-1 rows for each usercode, you can use LEAD() to get the next value and omit when this is null (i.e. the last row). The exception to this would be if there is only one row for a user, which you can avoid by always including the first row for every user. So you would end up with something like this:

WITH YourData AS
(	SELECT	ID, ApplicationID, UserCode
	FROM	(VALUES 
				(43641, 34, &#39;John&#39;),(43642, 52, &#39;John&#39;),(43643, 55, &#39;John&#39;), (43648, 55, &#39;Bill&#39;),
				(43645, 34, &#39;Steve&#39;),(43646, 52, &#39;Steve&#39;),(43647, 55, &#39;Steve&#39;),(43648, 56, &#39;Steve&#39;)
			) AS d (ID, ApplicationID, UserCode)
)
SELECT	d.UserCode, 
		ID_1 = d.RowNumber, 
		Data_1 = d.ApplicationID,
		ID_2 = CASE WHEN d.NextApplicationID IS NULL THEN NULL ELSE d.RowNumber + 1 END,
		Data_2 = d.NextApplicationID
FROM	(	SELECT	d.ID, 
					d.ApplicationID, 
					d.UserCode,
					RowNumber = ROW_NUMBER() OVER(PARTITION BY d.UserCode ORDER BY d.ApplicationID),
					NextApplicationID = LEAD(d.ApplicationID) OVER(PARTITION BY d.UserCode ORDER BY d.ApplicationID)
			FROM	YourData AS d
		) AS d
WHERE	d.NextApplicationID IS NOT NULL
OR		d.RowNumber = 1;

Which gives:

UserCode ID_1 Data_1 ID_2 Data_2
Bill 1 55 NULL NULL
John 1 34 2 52
John 2 52 3 55
Steve 1 34 2 52
Steve 2 52 3 55
Steve 3 55 4 56

Example on db<>fiddle

答案2

得分: 1

看起来相当简单,除非我漏看了什么。
您想要按它们的 id 排列的行 - 可能在相同的 user code 内,然后是应用程序 id、某个序列号、后续行的应用程序 id,以及递增了 1 的序列号。您不想显示在相同的 usercode 下没有后继的行。

WITH
indata(id, appid, usercode) AS (
            SELECT 43461, 34, 'john'
  UNION ALL SELECT 43462, 52, 'john'
  UNION ALL SELECT 43463, 55, 'john'
),
olap AS (
  SELECT
    usercode
  , ROW_NUMBER() OVER(PARTITION BY usercode ORDER BY id)   AS id_1
  , appid                                                  AS data_1
  , ROW_NUMBER() OVER(PARTITION BY usercode ORDER BY id) + 1 AS id_2
  , LEAD(appid)  OVER(PARTITION BY usercode ORDER BY id)   AS data_2
  FROM indata
)
SELECT
  *
FROM olap
WHERE data_2 IS NOT NULL;
-- 输出  usercode | id_1 | data_1 | id_2 | data_2 
-- 输出 ----------+------+--------+------+--------
-- 输出  john     |    1 |     34 |    2 |     52
-- 输出  john     |    2 |     52 |    3 |     55
英文:

Looks straightforward enough, unless I've overlooked something.
You want to show the rows ordered by their id - probably within the same user code , and then the application id, some sequence number, the application id of the succeeding row, and the sequence number incremented by 1. And you don't want to show rows that have no successor, within the same usercode .

WITH
indata(id,appid,usercode) AS (
            SELECT 43461,34,&#39;john&#39;
  UNION ALL SELECT 43462,52,&#39;john&#39;
  UNION ALL SELECT 43463,55,&#39;john&#39;
)
,
olap AS (
  SELECT
    usercode
  , ROW_NUMBER() OVER(PARTITION BY usercode ORDER BY id)   AS id_1
  , appid                                                  AS data_1
  , ROW_NUMBER() OVER(PARTITION BY usercode ORDER BY id)+1 AS id_2
  , LEAD(appid)  OVER(PARTITION BY usercode ORDER BY id)   AS data_2
  FROM indata
)
SELECT
  *
FROM olap
WHERE data_2 IS NOT NULL;
-- out  usercode | id_1 | data_1 | id_2 | data_2 
-- out ----------+------+--------+------+--------
-- out  john     |    1 |     34 |    2 |     52
-- out  john     |    2 |     52 |    3 |     55

答案3

得分: 1

看起来你正在尝试将相邻行转换为一个范围,所以如果对于每个用户代码你有10行,你想要生成9个输出行,每个行中包含当前和“下一个”ApplicationID值。你可以使用LEAD或LAG函数来实现这一点。

给定以下数据:

declare @TEMP table(
    ID INT,
    ApplicationId INT,
    usercode NVARCHAR(50)
)

insert into @temp (ID,ApplicationId,usercode)
values
(43461,34,'john'),
(43462,52,'john'),
(43463,55,'john');

下面的查询将产生所需的结果:

with a as(
SELECT usercode,
	row_number() over (partition by usercode order by id) as RN,
	applicationid,
	lag(applicationid) over (partition by usercode order by id) as Prev
from @temp)
SELECT 
    usercode,
    rn-1 as ID_1 ,
    prev as data_1,
    rn as ID_2,
    applicationid as data_2
from a
where prev is not null

这将返回:

usercode	ID_1	data_1	ID_2	data_2
john	    1	    34	    2	    52
john	    2	    52	    3	    55

over (partition by usercode order by id) 将数据按照usercode进行分区,并按照ID进行排序。之后,我们可以计算分区内的行号,并使用LAGLEAD检索前一个或下一个值。

LAG/LEAD 在边界处会返回NULL,因此使用 prev is not null 来排除边界对。

英文:

It looks like you're trying to convert adjacent rows into a range, so if for each usercode you have 10 rows, you want to produce 9 output rows, each with the current and "next" ApplicationID value. You can do that using the LEAD or LAG functions.

Given this data:

declare @TEMP table(
    ID INT,
    ApplicationId INT,
    usercode NVARCHAR(50)
)

insert into @temp (ID,ApplicationId,usercode)
values
(43461,34,&#39;john&#39;),
(43462,52,&#39;john&#39;),
(43463,55,&#39;john&#39;);

The following query will produce the desired result:

with a as(
SELECT usercode,
	row_number() over (partition by usercode order by id) as RN,
	applicationid,
	lag(applicationid) over (partition by usercode order by id) as Prev
from @temp)
SELECT 
    usercode,
    rn-1 as ID_1 ,
    prev as data_1,
    rn as ID_2,
    applicationid as data_2
from a
where prev is not null

This returns

usercode	ID_1	data_1	ID_2	data_2
john	    1	    34	    2	    52
john	    2	    52	    3	    55

over (partition by usercode order by id) partitions the data by usercode and orders it by ID. After that, we can calculate the row number in the partition and retrieve the previous or next value using LAG or LEAD.

LAG/LEAD will return NULL at the edges, so prev is not null is used to exclude the edge pair.

huangapple
  • 本文由 发表于 2023年1月9日 16:56:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/75054973.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定