英文:
Displaying Data In MS SQL Server With Same Key But Different ID
问题
以下是已经翻译好的部分:
让我们假设我有下面的数据:
如何在没有使用 UNION
的情况下按最低的 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
How can I display this data side by side with lowest id and so on without UNION
?
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 |
英文:
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, '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;
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 |
答案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,'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;
-- 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
进行排序。之后,我们可以计算分区内的行号,并使用LAG
或LEAD
检索前一个或下一个值。
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,'john'),
(43462,52,'john'),
(43463,55,'john');
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论