开发者社区> 问答> 正文

如何在SQL中的表中确定一系列人员的收益或损失百分比

我已经发布了一些有关我要编写的系统的问题,对问这么多问题感到很沮丧。但是,对于SQL Server的高级元素,我还是一个新手(或者是几年前的重访),所以请原谅并帮助我!

我已将数据从JSON导入到表中,该表中包含许多不同的信息,其中之一是随着时间的推移记录的人的体重。我有以下代码来生成此代码:

SELECT ServiceUserID, PersonID, ServiceUser, DateDone, [Weight]
FROM
(    SELECT ServiceUserID, PersonID, ServiceUser, DateDone, LEFT(SUBSTRING(cn.Fragment, PATINDEX('%[0-9.-]%', cn.Fragment), 8000),
           PATINDEX('%[^0-9.-]%', SUBSTRING(cn.Fragment, PATINDEX('%[0-9.-]%', cn.Fragment), 8000) + 'X') -1) AS [Weight], ra.ScoreMeaning
FROM [JSONCareNotes-HOME] cn 

LEFT OUTER JOIN [JSONRAs-HOME] ra ON ra.PersonID = cn.ServiceUserID

WHERE cn.SliderData LIKE '%weigh%'
and cn.Fragment NOT LIKE '%weighed%'
) AS SubQueryAlias

WHERE NOT ([Weight] IS NULL OR [Weight] = ' ')
ORDER BY ServiceUser, DateDone DESC
我从中得到的是(一个样本):

7e54d569-0ad2-43a9-aada-5f37480fdfd4    NULL    Resident 1      2019-11-16  83.1
19e0d4b1-8fe4-4480-b99b-5d067123121e    NULL    Resident 2      2019-11-16  63.8
ba2a406f-2e28-4186-a5a0-95d93bb20ca9    NULL    Resident 3      2019-11-10  54
ecfa663b-3dd2-4aef-b25c-e43dd6b82ebb    NULL    Resident 4      2019-11-16  81.5
8a5880af-1d7f-4b96-ae28-4de4fb1a4685    NULL    Resident 5      2019-11-28  60.9
8a5880af-1d7f-4b96-ae28-4de4fb1a4685    NULL    Resident 5      2019-11-21  61
8a5880af-1d7f-4b96-ae28-4de4fb1a4685    NULL    Resident 5      2019-11-01  62.05
91495cd7-054d-47d5-9be0-dd3123342f19    NULL    Resident 6      2019-11-16  52.9
be79adef-01c2-4fe9-86b1-9d42fe9fe012    NULL    Resident 7      2019-11-28  45.8

我想要下面的输出,以居民5为例:

Resident Name   Date        Value   %age Change
Resident 5      2019-11-01  62.05   n/a              
                2019-11-21  61      -1.69 
                2019-11-28  60.9    -1.85

最终,我希望能够说出从第一个日期,或者从通过变量输入的日期到最后一个日期或另一个定义的结束日期变量,列表中每个居民的百分比变化。大多数居民都会有很多条目,我只是想举一个例子。

如果这是在Delphi之类的地方(我知道是旧学校),那么这将相对容易。但是,出于清楚的原因,我正在尝试在SQL Server中进行尽可能多的处理。谁能提供任何指导?我知道使用LAG可能会找到上一行用作比较,但是我发现很难一次遍历整个EACH居民的整个表,然后生成那种列表以上。或者,最好只是遍历整个表,然后为每个人运行一个理货(这似乎是一条更为复杂的路线)。

谢谢蚂蚁

编辑(20/12)

感谢@Zhorov,我现在非常亲密。但是,虽然在div / 0出现之前我似乎无法获得多达10个条目的准确结果,但现在我的得分很高,我敢肯定,这是因为我搞砸了实施您的建议的方法。现在的代码是

;WITH cte AS (SELECT ServiceUserID, ra.PersonID, ServiceUser, cn.DateDone, TRY_CAST((LEFT(SUBSTRING(cn.Fragment, PATINDEX('%[0-9.-]%', cn.Fragment), 8000),
           PATINDEX('%[^0-9.-]%', SUBSTRING(cn.Fragment, PATINDEX('%[0-9.-]%', cn.Fragment), 8000) + 'X') -1)) AS REAL) AS [Weight], ra.ScoreMeaning
FROM [JSONCareNotes-HOME] cn 
LEFT OUTER JOIN [JSONRAs-HOME] ra ON ra.PersonID = cn.ServiceUserID
WHERE cn.SliderData LIKE '%weigh%'
AND cn.Fragment NOT LIKE '%weighed%'
)     
SELECT 
    ServiceUser,
    DateDone,
    [Weight],
    CASE 
       WHEN FIRST_VALUE([Weight] ) OVER (PARTITION BY [ServiceUser] ORDER BY DateDone ASC) = 0 THEN 0
       ELSE CONVERT(
               numeric(10, 2),
               [Weight] - FIRST_VALUE([Weight]) OVER (PARTITION BY [ServiceUser] ORDER BY DateDone ASC) / 
               FIRST_VALUE([Weight]) OVER (PARTITION BY [ServiceUser] ORDER BY DateDone ASC) * 
               100.0
            ) 
    END
    AS [Percentage]
FROM cte 
WHERE NOT([Weight] IS NULL) OR [Weight] = ' '
ORDER BY ServiceUser, DateDone ASC

这给了我以下结果:

Resident 1  2019-11-16  83.1    -16.90
Resident 2  2019-11-16  63.8    -36.20
Resident 3  2019-11-10  54      -46.00
Resident 4  2019-11-16  81.5    -18.50
Resident 5  2019-11-01  62.05   -37.95
Resident 5  2019-11-21  61      -39.00
Resident 5  2019-11-28  60.9    -39.10
Resident 6  2019-11-16  52.9    -47.10
Resident 7  2019-11-14  40      -60.00
Resident 7  2019-11-21  42      -58.00
Resident 7  2019-11-28  45.8    -54.20
Resident 8  2019-11-21  48.1    -51.90
Resident 8  2019-11-28  50.2    -49.80

我在某处想念东西!谁能为我找到它?我认为不是每个新居民都会重置吗?

展开
收起
祖安文状元 2020-01-05 14:52:50 457 0
1 条回答
写回答
取消 提交回答
  • 更新:

    看来,您的[Weight]列将数字保存为文本。尝试使用TRY_CONVERT()(numeric(10, 2)只是测试数据类型,请使用适当的数字数据类型)转换这些值。一种可能的方法是:

    SELECT ServiceUserID, PersonID, ServiceUser, DateDone, [Weight]
    FROM (
        SELECT 
            ServiceUserID, 
            PersonID, 
            ServiceUser, 
            DateDone, 
            TRY_CONVERT(
                numeric(10, 2),
                LEFT(SUBSTRING(cn.Fragment, PATINDEX('%[0-9.-]%', cn.Fragment), 8000), PATINDEX('%[^0-9.-]%', SUBSTRING(cn.Fragment, PATINDEX('%[0-9.-]%', cn.Fragment), 8000) + 'X') -1)
            ) AS [Weight], 
            ra.ScoreMeaning
        FROM [JSONCareNotes-HOME] cn 
        LEFT OUTER JOIN [JSONRAs-HOME] ra ON ra.PersonID = cn.ServiceUserID
        WHERE cn.SliderData LIKE '%weigh%' and cn.Fragment NOT LIKE '%weighed%'
        ) AS SubQueryAlias
    WHERE [Weight] IS NOT NULL
    ORDER BY ServiceUser, DateDone DESC
    
    2020-01-05 14:53:02
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
SQL Server 2017 立即下载
GeoMesa on Spark SQL 立即下载
原生SQL on Hadoop引擎- Apache HAWQ 2.x最新技术解密malili 立即下载