SQL如何不基于行计算中值

SQL如何不基于行计算中值,sql,sql-server,median,Sql,Sql Server,Median,我的表中有一个汽车样本,我想用SQL计算样本的中间价。最好的方法是什么 +-----+-------+----------+ | Car | Price | Quantity | +-----+-------+----------+ | A | 100 | 2 | | B | 150 | 4 | | C | 200 | 8 | +-----+-------+----------+ 我知道如果我的表格如下所示,我可以使用perce

我的表中有一个汽车样本,我想用SQL计算样本的中间价。最好的方法是什么

+-----+-------+----------+
| Car | Price | Quantity |
+-----+-------+----------+
| A   |   100 |        2 |
| B   |   150 |        4 |
| C   |   200 |        8 |
+-----+-------+----------+
我知道如果我的表格如下所示,我可以使用percentile_cont或percentile_disc:

+-----+-------+
| Car | Price |
+-----+-------+
| A   |   100 |
| A   |   100 |
| B   |   150 |
| B   |   150 |
| B   |   150 |
| B   |   150 |
| C   |   200 |
| C   |   200 |
| C   |   200 |
| C   |   200 |
| C   |   200 |
| C   |   200 |
| C   |   200 |
| C   |   200 |
+-----+-------+

但在现实世界中,我的第一张桌子有大约1亿行,第二张桌子应该有大约3行台球,而且我不知道如何将我的第一张桌子转换成第二张桌子。

这在一些结果上看起来是正确的,但试着用一个更大的集合进行双重检查

首先创建一个表,其中包含每辆车的总数,或者使用CTE或子查询(由您选择)。我只是在这里创建一个单独的表

    create table table2 as
    (
        select car, 
        quantity, 
        price, 
        price * quantity as total
        from table1
    )

然后运行此查询,查找属于中间的价格组。

    select price
    from (
        select car, price, 
        sum(total) over (order by car) as rollsum, 
        sum(total) over () as total
        from table2
        )a
    where rollsum >= total/2

正确返回$200的值。

这在少数结果中看起来是正确的,但请尝试在更大的集合中进行双重检查

首先创建一个表,其中包含每辆车的总数,或者使用CTE或子查询(由您选择)。我只是在这里创建一个单独的表

    create table table2 as
    (
        select car, 
        quantity, 
        price, 
        price * quantity as total
        from table1
    )

然后运行此查询,查找属于中间的价格组。

    select price
    from (
        select car, price, 
        sum(total) over (order by car) as rollsum, 
        sum(total) over () as total
        from table2
        )a
    where rollsum >= total/2

正确返回$200的值。

以下是在sql server中执行此操作的一种方法

在第一步中,我要做的是计算与中位数的上下限相对应的索引,如果我们有奇数个元素,那么上下限是相同的,否则它基于x/2和x/2+1的值

然后我得到数量的累积和,并使用它来选择对应于上下限的元素,如下所示

with median_dt
  as (
select case when sum(quantity)%2=0 then
                 sum(quantity)/2 
            else 
                 sum(quantity)/2 + 1
        end as lower_limit
      ,case when sum(quantity)%2=0 then
                 (sum(quantity)/2) + 1
            else 
                 sum(quantity)/2 + 1
        end as upper_limit  
 from t 
     )
    ,data
    as (
 select *,sum(quantity) over(order by price asc) as cum_sum
   from t
       )
   ,rnk_val
   as(select * 
       from (
             select price,row_number() over(order by d.cum_sum asc) as rnk
               from data d
               join median_dt b
                 on b.lower_limit<=d.cum_sum
             )x 
      where x.rnk=1
      union all 
     select * 
       from (
             select price,row_number() over(order by d.cum_sum asc) as rnk
               from data d
               join median_dt b
                 on b.upper_limit<=d.cum_sum
             )x 
      where x.rnk=1
      ) 
  select avg(price) as median
    from rnk_val



+--------+
| median |
+--------+
|    200 |
+--------+
小提琴链接
以下是在sql server中执行此操作的一种方法

在第一步中,我要做的是计算与中位数的上下限相对应的索引,如果我们有奇数个元素,那么上下限是相同的,否则它基于x/2和x/2+1的值

然后我得到数量的累积和,并使用它来选择对应于上下限的元素,如下所示

with median_dt
  as (
select case when sum(quantity)%2=0 then
                 sum(quantity)/2 
            else 
                 sum(quantity)/2 + 1
        end as lower_limit
      ,case when sum(quantity)%2=0 then
                 (sum(quantity)/2) + 1
            else 
                 sum(quantity)/2 + 1
        end as upper_limit  
 from t 
     )
    ,data
    as (
 select *,sum(quantity) over(order by price asc) as cum_sum
   from t
       )
   ,rnk_val
   as(select * 
       from (
             select price,row_number() over(order by d.cum_sum asc) as rnk
               from data d
               join median_dt b
                 on b.lower_limit<=d.cum_sum
             )x 
      where x.rnk=1
      union all 
     select * 
       from (
             select price,row_number() over(order by d.cum_sum asc) as rnk
               from data d
               join median_dt b
                 on b.upper_limit<=d.cum_sum
             )x 
      where x.rnk=1
      ) 
  select avg(price) as median
    from rnk_val



+--------+
| median |
+--------+
|    200 |
+--------+
小提琴链接

您试过这个吗?所有方法都适用于我的第二个表,而不是第一个表。这将是平均价格,而不是中间价。请标记您使用的数据库George Joseph,我有两个数据库-Oracle和SQL Server。您尝试过这个吗?所有方法都适用于我的第二个表,而不是第一个Jarlh,这将是平均价格而不是中间价请标记您使用的数据库George Joseph,我有两个DB-Oracle和SQL服务器,我认为如果相同的值有一半以上的行数,这将不起作用……我在额外的步骤中使用了相同的方法,我选择了最接近50%的价格组。但我想使用percintle_CONT中的线性插值,我希望它在我的样本中只有一个点时起作用。我认为如果同一个值的行数超过一半,这将不起作用……我在额外步骤中使用了相同的方法,我选择了最接近50%的价格组。但是我想使用线性插值,就像percintle_CONT一样,我希望它在我的样本中只有一个点时工作。