How to convert the Partition function in Access for use in Microsoft SQL Server?

我怕爱的太早我们不能终老 提交于 2020-01-25 20:50:47

问题


I have used MS Access a lot, but I was recently asked to help with a SQL Server database. I noticed that simply copying the SQL code from Access over to the server database doesn't work. Could someone please help me replicate the functionality of my SQL code from Access into SQL Server?

Below is the SQL View that works within Access:

SELECT [LV1]-[LV2] AS Aging, Partition([Aging],1,100,10) AS AgingRange

FROM Table1;

Aging is a calculated column based off of two columns within my table. I want to partition it using SQL Server as seen below.


回答1:


The following T-SQL scalar-valued function seems to work:

-- =============================================
-- Author:      Gord Thompson
-- Create date: 2016-07-30
-- Description: like Partition function in Access
-- =============================================
CREATE FUNCTION [dbo].[myPartition] 
(
    @Number int, @Start int, @Stop int, @Interval int
)
RETURNS varchar(max)
AS
BEGIN

    DECLARE @Result varchar(max), @x int, @y int;

    IF @Number is null OR @Start is null OR @Stop is null OR @Interval is null 
            OR @Interval < 1 OR (@Stop - @Start) < 2
    BEGIN
        SELECT @Result = null;
    END
    ELSE
    BEGIN
        IF @Number < @Start 
        BEGIN
            SELECT @Result = ':' + CONVERT(varchar(max), @Start -1);
        END
        ELSE
        BEGIN
            IF @Number > @Stop
            BEGIN
                SELECT @Result = CONVERT(varchar(max), @Stop + 1) + ':';
            END
            ELSE
            BEGIN
                SELECT @x = @Start, @y = @Start + @Interval - 1
                WHILE NOT (@Number >= @x AND @Number <= @y)
                BEGIN
                    SELECT @x = @x + @Interval, @y = @y + @Interval;
                    IF @y > @Stop
                    BEGIN
                        SELECT @y = @Stop;
                    END
                END
                SELECT @Result = CONVERT(varchar(max), @x) + ':' + CONVERT(varchar(max), @y);
            END
        END
    END
    RETURN @Result

END

GO



回答2:


I assume that you are aggregating inside the partitions, if not then please ignore as it is a sign of my ignorance what access calls a partition function.

I would create a temp table to define a set of right or left partitions. Next, INNER JOIN data from your table BETWEEN low and high range. This will work only if Aging is an aggregate function.

DECLARE @DataPartitions TABLE(Low INT,High INT)

INSERT @DataPartitions SELECT 0,10
INSERT @DataPartitions SELECT 11,20
INSERT @DataPartitions SELECT 21,30
INSERT @DataPartitions SELECT 31,40
INSERT @DataPartitions SELECT 41,50

SELECT 
    Aging=AVG(T.Value1)-AVG(T.Value2),
    CAST(MIN(P.Low) AS NVARCHAR(10))+":"+CAST(MAX(P.High) AS NVARCHAR(10))
FROM
    MyTable T
    INNER JOIN @DataPartitions P ON T.Value BETWEEN P.Low AND P.High
GROUP BY
    P.High



回答3:


I duplicated most of the behavior from the partition documentation. It's a fairly concise expression though I didn't attempt to handle ranges that include negative numbers because it's not clear to me whether the extra space character is supposed to be used for a minus sign or just padding. And since I'm assuming that, stop must be strictly greater than start and so it can't be negative and thus I didn't have to avoid taking the logarithm of zero. My version below does adapt the length appropriately which is where the logarithm comes into play.

Since partition is a reserved word in SQL Server you'll probably want to change the name. Note that all the values are integers and the division operations are used because the remainder is discarded.

create function dbo.[partition] as (
    @number int, @start int, @stop int, @interval int
)
returns varchar(32) as begin
return
   case
      when @number < @start then ' :' + cast(@start - 1 as varchar(10)) + ' '
      when @number > @stop  then ' '  + cast(@stop  + 1 as varchar(10)) + ': '
      else
         right(
            '          ' + cast(
               @start + (@number - @start) / @interval * @interval as varchar(10)
            ),
            floor(log(@stop) / log(10)) + 2
         ) + ':' +
         right(
            '          ' + cast( 
               case
                  when @start + ((@number - @start) / @interval + 1) * @interval > @stop
                  then @stop
                  else @start + ((@number - @start) / @interval + 1) * @interval
               end as varchar(10)
            ),
            floor(log(@stop) / log(10)) + 2
         )
   end
end

If you're just needing the partition function to drive grouping I might argue to just use (@number - @start) / @interval (optionally in a case expression to handle the "before first" and "after last" ranges.)



来源:https://stackoverflow.com/questions/38667154/how-to-convert-the-partition-function-in-access-for-use-in-microsoft-sql-server

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!