স্ট্যান্ডার্ড এসকিউএল বা টি-এসকিউএল এর 1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1,… সিরিজ কিভাবে জেনারেট করবেন?


11

দুটি নম্বর দেওয়া nএবং m, আমি ফর্মের একটি সিরিজ উত্পন্ন করতে চাই

1, 2, ..., (n-1), n, n, (n-1), ... 2, 1

এবং এটি mবার বার।

উদাহরণস্বরূপ, এর জন্য n = 3এবং m = 4আমি নিম্নলিখিত 24 সংখ্যার ক্রম চাই:

1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1
----------------  ----------------  ----------------  ----------------

আমি জানি যে পোস্টগ্র্রেএসকিউএলএর দুটি পদ্ধতির মধ্যে দিয়ে কীভাবে এই ফলাফলটি অর্জন করা যায়:

নিম্নলিখিত কোয়েরিটি ব্যবহার করে, যা generate_seriesফাংশনটি ব্যবহার করে এবং এই আদেশটি সঠিক হওয়ায় গ্যারান্টি দিতে কয়েকটি কৌশল:

WITH parameters (n, m) AS
(
    VALUES (3, 5)
)
SELECT 
    xi
FROM
(
    SELECT
        i, i AS xi
    FROM
        parameters, generate_series(1, parameters.n) AS x(i)
    UNION ALL
    SELECT
        i + parameters.n, parameters.n + 1 - i AS xi
    FROM
        parameters, generate_series(1, parameters.n) AS x(i)
) AS s0 
CROSS JOIN 
    generate_series (1, (SELECT m FROM parameters)) AS x(j)
ORDER BY
    j, i ;

... বা একই উদ্দেশ্যে একটি কার্যকারিতা ব্যবহার করুন, স্থগিত এবং নেস্টেড লুপগুলি সহ:

CREATE FUNCTION generate_up_down_series(
    _elements    /* n */ integer,
    _repetitions /* m */ integer)
RETURNS SETOF integer AS
$BODY$
declare
    j INTEGER ;
    i INTEGER ;
begin
    for j in 1 .. _repetitions loop
        for i in         1 .. _elements loop
              return next i ;
        end loop ;
        for i in reverse _elements .. 1 loop
              return next i ;
        end loop ;
    end loop ;
end ;
$BODY$
LANGUAGE plpgsql IMMUTABLE STRICT ;

আমি কীভাবে সম্ভব স্ট্যান্ডার্ড এসকিউএল বা লেনদেন-এসকিউএল / এসকিউএল সার্ভারে সমতুল্য করতে পারি?

উত্তর:


4

পোস্টগ্র্রেসে, generate_series()ফাংশনটি ব্যবহার করা সহজ :

WITH 
  parameters (n, m) AS
  ( VALUES (3, 5) )
SELECT 
    CASE WHEN g2.i = 1 THEN gn.i ELSE p.n + 1 - gn.i END AS xi
FROM
    parameters AS p, 
    generate_series(1, p.n) AS gn (i),
    generate_series(1, 2)   AS g2 (i),
    generate_series(1, p.m) AS gm (i)
ORDER BY
    gm.i, g2.i, gn.i ;

স্ট্যান্ডার্ড এসকিউএল - এবং ধরে নেওয়া যে n, m, অর্থাৎ মিলিয়ন এর চেয়ে কম প্যারামিটারের আকারের একটি যুক্তিসঙ্গত সীমা রয়েছে - আপনি একটি Numbersটেবিল ব্যবহার করতে পারেন :

CREATE TABLE numbers 
( n int not null primary key ) ;

আপনার ডিবিএমএসের পছন্দের পদ্ধতিটি এটি পূরণ করুন:

INSERT INTO numbers (n)
VALUES (1), (2), .., (1000000) ;  -- some mildly complex SQL here
                                  -- no need to type a million numbers

এবং তারপরে এটি ব্যবহার করুন generate_series():

WITH 
  parameters (n, m) AS
  ( VALUES (3, 5) )
SELECT 
    CASE WHEN g2.i = 1 THEN gn.i ELSE p.n + 1 - gn.i END AS xi
FROM
    parameters AS p
  JOIN numbers AS gn (i) ON gn.i <= p.n
  JOIN numbers AS g2 (i) ON g2.i <= 2
  JOIN numbers AS gm (i) ON gm.i <= p.m 
ORDER BY
    gm.i, g2.i, gn.i ;

বাস্তবে, আমি আশা করি না যে এই সংখ্যাগুলি 100 এর চেয়ে বড় হবে; কিন্তু তত্ত্বত তারা কিছু হতে পারে।
joanolo

10

Postgres

আপনি এটি একটি একক generate_series() এবং বেসিক গণিত দিয়ে কাজ করতে পারেন ( গাণিতিক ফাংশন দেখুন )।

একটি সাধারণ এসকিউএল ফাংশনে আবৃত:

CREATE OR REPLACE FUNCTION generate_up_down_series(n int, m int)
  RETURNS SETOF int AS
$func$
SELECT CASE WHEN n2 < n THEN n2 + 1 ELSE n*2 - n2 END
FROM  (
   SELECT n2m, n2m % (n*2) AS n2
   FROM   generate_series(0, n*2*m - 1) n2m
   ) sub
ORDER  BY n2m
$func$  LANGUAGE sql IMMUTABLE;

কল করুন:

SELECT * FROM generate_up_down_series(3, 4);

কাঙ্ক্ষিত ফলাফল উত্পন্ন করে। এন এবং এম যে কোনও পূর্ণসংখ্যার হতে পারে যেখানে এন * 2 * মি ওভারফ্লো হয় না int4

কিভাবে?

সাবকিউরিতে:

  • একটি সহজ আরোহী সংখ্যা সহ সারিগুলির কাঙ্ক্ষিত মোট সংখ্যা ( এন * 2 * মি ) তৈরি করুন। নাম দিয়েছি n2m। নিম্নলিখিত মডুলো ক্রিয়াকলাপটি সহজ করার জন্য 0 থেকে এন -1 ( 1 থেকে এন নয় ) ।

  • নিয়ে নিন % N * 2 ( %ফরম অপারেটরের হয়) একটি সিরিজ পেতে এন আরোহী সংখ্যা, মি বার। নাম দিয়েছি n2

বাহ্যিক ক্যোয়ারিতে:

  • অর্ধেকে নীচে যোগ করুন ( এন 2 <এন )।

  • নীচের অর্ধেকের উপরের অর্ধেক ( n2> = n ) আয়নাটির জন্য n * 2 - n2 দিয়ে

  • আমি ORDER BYঅনুরোধ করা আদেশ গ্যারান্টি যোগ করা। বর্তমান সংস্করণ বা পোস্টগ্রিসের সাথে এটি ORDER BYসাধারণ কোয়েরি ছাড়াও কাজ করে - তবে অগত্যা আরও জটিল প্রশ্নগুলিতে নয়! এটি একটি বাস্তবায়নের বিশদ (এবং এটি পরিবর্তিত হবে না) তবে এসকিউএল স্ট্যান্ডার্ড দ্বারা ওয়্যারেন্টেড নয়।

দুর্ভাগ্যক্রমে, generate_series()পোস্টগ্র্রেস নির্দিষ্ট এবং স্ট্যান্ডার্ড এসকিউএল নয়, যেমনটি মন্তব্য করা হয়েছে। তবে আমরা একই যুক্তি পুনরায় ব্যবহার করতে পারি:

স্ট্যান্ডার্ড এসকিউএল

আপনি generate_series()বার বার ব্যবহারের জন্য আরও দক্ষতার পরিবর্তে পুনরাবৃত্ত সিটিই দিয়ে সিরিয়াল নম্বরগুলি তৈরি করতে পারেন, একবার সিরিয়াল পূর্ণসংখ্যার সংখ্যা সহ একটি টেবিল তৈরি করতে পারেন। যে কেউ পড়তে পারে, নুনি তাতে লিখতে পারে!

CREATE TABLE int_seq (i integer);

WITH RECURSIVE cte(i) AS (
   SELECT 0
   UNION ALL
   SELECT i+1 FROM cte
   WHERE  i < 20000  -- or as many you might need!
   )
INSERT INTO int_seq
SELECT i FROM cte;

তারপরে, SELECTউপরেরগুলি আরও সহজ হয়ে যায়:

SELECT CASE WHEN n2 < n THEN n2 + 1 ELSE n*2 - n2 END AS x
FROM  (
   SELECT i, i % (n*2) AS n2
   FROM   int_seq
   WHERE  i < n*2*m  -- remember: 0 to N-1
   ) sub
ORDER  BY i;

5

আপনার যদি সরল এসকিউএল প্রয়োজন হয়। তাত্ত্বিকভাবে সর্বাধিক ডিবিএমএস (পোস্টগ্র্রেএসকিউএল এবং এসকিউএলাইটে পরীক্ষা করা) নিয়ে কাজ করা উচিত :

with recursive 
  s(i,n,z) as (
    select * from (values(1,1,1),(3*2,1,2)) as v  -- Here 3 is n
    union all
    select
      case z when 1 then i+1 when 2 then i-1 end, 
      n+1,
      z 
    from s 
    where n < 3), -- And here 3 is n
  m(m) as (select 1 union all select m+1 from m where m < 2) -- Here 2 is m

select n from s, m order by m, i;

ব্যাখ্যা

  1. সিরিজ উত্পন্ন 1..n

    ধরে নিচ্ছি যে n=3

    with recursive s(n) as (
      select 1
      union all
      select n+1 from s where n<3
    )
    select * from s;
    

    এটি বেশ সহজ এবং পুনরাবৃত্ত সিটিই সম্পর্কে প্রায় কোনও ডক্সে এটি পাওয়া যায়। তবে পুঁচকে প্রতিটি মানের দুটি উদাহরণ প্রয়োজন

  2. সিরিজ 1,1, .., এন, এন জেনারেট করুন

    with recursive s(n) as (
      select * from (values(1),(1)) as v
      union all
      select n+1 from s where n<3
    )
    select * from s;
    

    এখানে আমরা কেবলমাত্র প্রাথমিক মান দ্বিগুণ করছি যার দুটি সারি রয়েছে, তবে দ্বিতীয় গুচ্ছটি আমাদের বিপরীত ক্রমে প্রয়োজন, তাই আমরা কিছুটা অর্ডারটি প্রবর্তন করব।

  3. আমরা অর্ডার প্রবর্তন করার আগে পর্যবেক্ষণ করুন যে এটিও একটি জিনিস। প্রত্যেকে তিনটি কলাম সহ প্রারম্ভিক অবস্থায় দুটি সারি থাকতে পারে, আমাদের n<3এখনও একটি একক কলাম শর্তাধীন। এবং, আমরা এখনও কেবল এর মান বাড়িয়ে চলেছি n

    with recursive s(i,n,z) as (
      select * from (values(1,1,1),(1,1,1)) as v
      union all
      select
        i,
        n+1,
        z 
      from s where n<3
    )
    select * from s;
    
  4. তেমনি, আমরা সেগুলি কিছুটা মিশিয়ে দিতে পারি, আমাদের শুরু শর্তটি এখানে দেখুন watch এখানে আমাদের একটি (6,2),(1,1)

    with recursive s(i,n,z) as (
      select * from (values(1,1,1),(6,1,2)) as v
      union all
      select
        i,
        n+1,
        z 
      from s where n<3
    )
    select * from s;
    
  5. সিরিজ উত্পন্ন 1..n, n..1

    কৌতুকটি হ'ল দুইবার সিরিজ উত্পন্ন করা (1..n) এবং তারপরে দ্বিতীয় সেটটিতে ক্রম পরিবর্তন করুন।

    with recursive s(i,n,z) as (
      select * from (values(1,1,1),(3*2,1,2)) as v
      union all
      select
        case z when 1 then i+1 when 2 then i-1 end, 
        n+1,
        z 
      from s where n<3
    )
    select * from s order by i;
    

    এখানে iঅর্ডার এবং zক্রম সংখ্যা (বা আপনি চাইলে ক্রমের অর্ধেক)। সিকোয়েন্স 1 এর জন্য আমরা 1 থেকে 3 ক্রম বাড়িয়ে দিচ্ছি এবং সিকোয়েন্স 2 এর জন্য আমরা অর্ডারটি 6 থেকে 4 থেকে কমিয়ে আছি এবং অবশেষে

  6. সিরিজটির গুণিত করুন m

    (উত্তরের প্রথম প্রশ্নটি দেখুন)


3

আপনি যদি কোনও পোর্টেবল সমাধান চান তবে আপনার বুঝতে হবে এটি মূলত একটি গাণিতিক সমস্যা।

@ ক্রমটির সর্বাধিক সংখ্যার হিসাবে এবং @ x কে এই অনুক্রমের সংখ্যার অবস্থান হিসাবে দেওয়া (শূন্য দিয়ে শুরু), নিম্নলিখিত ফাংশনটি এসকিউএল সার্ভারে কাজ করবে:

CREATE FUNCTION UpDownSequence
(
    @n int, -- Highest number of the sequence
    @x int  -- Position of the number we need
)
RETURNS int
AS
BEGIN
    RETURN  @n - 0.5 * (ABS((2*((@x % (@n+@n))-@n)) +1) -1)
END
GO

আপনি এই সিটিই দিয়ে এটি পরীক্ষা করতে পারেন:

DECLARE @n int=3;--change the value as needed
DECLARE @m int=4;--change the value as needed

WITH numbers(num) AS (SELECT 0 
                      UNION ALL
                      SELECT num+1 FROM numbers WHERE num+1<2*@n*@m) 
SELECT num AS Position, 
       dbo.UpDownSequence(@n,num) AS number
FROM numbers
OPTION(MAXRECURSION 0)

(দ্রুত ব্যাখ্যা: ফাংশনটি পুনরাবৃত্তি সংখ্যাগুলির ক্রম তৈরি করতে এবং এ.বি.এস.) এটিকে জিগ-জাগ তরঙ্গে পরিণত করার জন্য মোডুলো () ব্যবহার করে other


2

পোস্টগ্র্যাস এসকিউএল এ, এটি সহজ,

CREATE OR REPLACE FUNCTION generate_up_down_series(n int, m int)
RETURNS setof int AS $$
SELECT x FROM (
  SELECT 1, ordinality AS o, x FROM generate_series(1,n) WITH ORDINALITY AS t(x)
  UNION ALL
  SELECT 2, ordinality AS o, x FROM generate_series(n,1,-1) WITH ORDINALITY AS t(x)
) AS t(o1,o2,x)
CROSS JOIN (
  SELECT * FROM generate_series(1,m)
) AS g(y)
ORDER BY y,o1,o2
$$ LANGUAGE SQL;

2

এটি এমএস-এসকিউএল-তে কাজ করে এবং আমি মনে করি যে কোনও এসকিউএল স্বাদে পরিবর্তন করা যেতে পারে।

declare @max int, @repeat int, @rid int

select @max = 3, @repeat = 4

-- create a temporary table
create table #temp (row int)

--create seed rows
while (select count(*) from #temp) < @max * @repeat * 2
begin
    insert into #temp
    select 0
    from (values ('a'),('a'),('a'),('a'),('a')) as a(col1)
    cross join (values ('a'),('a'),('a'),('a'),('a')) as b(col2)
end

-- set row number can also use identity
set @rid = -1

update #temp
set     @rid = row = @rid + 1

-- if the (row/max) is odd, reverse the order
select  case when (row/@max) % 2 = 1 then @max - (row%@max) else (row%@max) + 1 end
from    #temp
where   row < @max * @repeat * 2
order by row

2

পুনরাবৃত্ত cte ব্যবহার করে এসকিউএল সার্ভারে এটি করার একটি উপায়।

1) সিরিজে প্রয়োজনীয় সংখ্যক সদস্য তৈরি করুন (এন = 3 এবং মি = 4 এর জন্য এটি 24 হবে যা 2 * এন * মি)

2) এর পরে একটি caseঅভিব্যক্তিতে যুক্তি ব্যবহার করে , আপনি প্রয়োজনীয় সিরিজ তৈরি করতে পারেন।

Sample Demo

declare @n int=3;--change the value as needed
declare @m int=4;--change the value as needed

with numbers(num) as (select 1 
                      union all
                      select num+1 from numbers where num<2*@n*@m) 
select case when (num/@n)%2=0 and num%@n<>0 then num%@n 
            when (num/@n)%2=0 and num%@n=0 then 1  
            when (num/@n)%2=1 and num%@n<>0 then @n+1-(num%@n)  
            when (num/@n)%2=1 and num%@n=0 then @n
       end as num
from numbers
OPTION(MAXRECURSION 0)

@ অ্যান্ড্রিএম দ্বারা প্রস্তাবিত হিসাবে .. caseএক্সপ্রেশনটি সরল করা যেতে পারে

with numbers(num) as (select 0
                      union all
                      select num+1 from numbers where num<2*@n*@m-1) 
select case when (num/@n)%2=0 then num%@n + 1
            when (num/@n)%2=1 then @n - num%@n
       end as num
from numbers
OPTION(MAXRECURSION 0)

Demo


2

শুধুমাত্র বেসিক ম্যাথ + - * /এবং মডুলো ব্যবহার :

SELECT x
    , s = x % (2*@n) +
         (1-2*(x % @n)) * ( ((x-1) / @n) % 2)
FROM (SELECT TOP(2*@n*@m) x FROM numbers) v(x)
ORDER BY x;

এর জন্য কোনও নির্দিষ্ট এসজিবিডি প্রয়োজন হয় না।

সঙ্গে numbersএকটি সংখ্যা টেবিল হচ্ছে:

...; 
WITH numbers(x) AS(
    SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
    FROM (VALUES(0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) AS n0(x)
    CROSS JOIN (VALUES(0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) AS n1(x)
    CROSS JOIN (VALUES(0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) AS n2(x)
)
...

এটি পুনরাবৃত্তিযোগ্য সিটিই ব্যবহার না করে একটি সংখ্যা সারণী (1-1000) উত্পন্ন করে। নমুনা দেখুন । 2 * n * মি সংখ্যার সারি সংখ্যার চেয়ে কম হওয়া উচিত।

এন = 3 এবং মি = 4 দিয়ে আউটপুট:

x   s
1   1
2   2
3   3
4   3
5   2
6   1
7   1
8   2
... ...

এই সংস্করণটির জন্য একটি ছোট সংখ্যার টেবিলের প্রয়োজন (v> = n এবং v> = মি):

WITH numbers(v) AS(
    SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
    FROM (VALUES(1), (2), (3), (4), (5), (6), ...) AS n(x)
)
SELECT ord = @n*(v+2*m) + n
    , n*(1-v) + ABS(-@n-1+n)*v
FROM (SELECT TOP(@n) v FROM numbers ORDER BY v ASC) n(n)
CROSS JOIN (VALUES(0), (1)) AS s(v)
CROSS JOIN (SELECT TOP(@m) v-1 FROM numbers ORDER BY v ASC) m(m)
ORDER BY ord;

নমুনা দেখুন ।


2

পুনরুক্তি ব্যবহার করে একটি প্রাথমিক ফাংশন।

টি-এসকিউএল

create function generate_up_down_series(@max int, @rep int)
returns @serie table
(
    num int
)
as
begin

    DECLARE @X INT, @Y INT;
    SET @Y = 0;

    WHILE @Y < @REP
    BEGIN

        SET @X = 1;
        WHILE (@X <= @MAX)
        BEGIN
            INSERT @SERIE
            SELECT @X;
            SET @X = @X + 1;
        END

        SET @X = @MAX;
        WHILE (@X > 0)
        BEGIN
            INSERT @SERIE
            SELECT @X;
            SET @X = @X -1;
        END

        SET @Y = @Y + 1;
    END

    RETURN;
end
GO

Postgres

create or replace function generate_up_down_series(maxNum int, rep int)
returns table (serie int) as
$body$
declare
    x int;
    y int;
    z int;
BEGIN

    x := 0;
    while x < rep loop

        y := 1;
        while y <= maxNum loop
            serie := y;
            return next;
            y := y + 1;
        end loop;

        z := maxNum;
        while z > 0 loop
            serie := z;
            return next;
            z := z - 1;
        end loop;

        x := x + 1;
    end loop;

END;
$body$ LANGUAGE plpgsql;

1
declare @n int = 5;
declare @m int = 3;
declare @t table (i int, pk int identity);
WITH  cte1 (i) 
AS ( SELECT 1
     UNION ALL
     SELECT i+1 FROM cte1
     WHERE  i < 100  -- or as many you might need!
   )
insert into @t(i) select i from cte1 where i <= @m  order by i
insert into @t(i) select i from @t order by i desc
select t.i --, t.pk, r.pk 
from @t as t 
cross join (select pk from @t where pk <= @n) as r
order by r.pk, t.pk
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.