Print Prime Numbers with SQL query

橙三吉。 提交于 2020-01-12 07:51:46

问题


I am new to StackOverflow and have got stuck with a query to print prime numbers from 2 to 1000. I have used the below query need input if this is the most efficient way to code it.

WITH NUM AS (
    SELECT LEVEL N 
    FROM DUAL CONNECT BY LEVEL <= 1000
) 
SELECT LISTAGG(B.N,'-') WITHIN GROUP(ORDER BY B.N) AS PRIMES 
FROM (
    SELECT  N,
            CASE WHEN EXISTS (
                                SELECT NULL 
                                FROM NUM N_INNER 
                                WHERE N_INNER .N > 1 
                                AND N_INNER.N < NUM.N 
                                AND MOD(NUM.N, N_INNER.N)=0
                            ) THEN 
                'NO PRIME' 
            ELSE 
                'PRIME' 
            END IS_PRIME 
        FROM NUM
    ) B 
WHERE B.IS_PRIME='PRIME' 
AND B.N!=1;

I know this question has been asked multiple times and I am requesting better solution if any. More over need input on how this works with MySQL/MS SQL/PostgreSQL.

Any help will make my understanding better.


回答1:


In PostgreSQL probably the most fastest query that prints prime numbers up to 1000 is:

SELECT regexp_split_to_table('2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997',E',')::int
AS x
;

It took only 16 ms on my computer.

  • Note: a list of prime numbers was copied from https://en.wikipedia.org/wiki/Prime_number
    and pasted into this long string

If you prefer SQL, then this works

WITH x AS (
  SELECT * FROM generate_series( 2, 1000 ) x
)
SELECT x.x
FROM x
WHERE NOT EXISTS (
  SELECT 1 FROM x y
  WHERE x.x > y.x AND x.x % y.x = 0
)
;

It's two times slower - 31 ms.


Ans an equivalent version for Oracle:

WITH x AS(
    SELECT level+1 x
    FROM dual
    CONNECT BY LEVEL <= 999
)
SELECT x.x
FROM x
WHERE NOT EXISTS (
  SELECT 1 FROM x y
  WHERE x.x > y.x AND remainder( x.x, y.x) = 0
)
;



回答2:


The most obvious improvement is that instead of checking from 1 to n you can check from 1 to the square root of n.

A second major optimization would be to use a temporary table to store the results and check them first. This way you can iterate incrementally from 1 to n, and only check the known primes from 1 to square root of n (recursively doing that until you have a list). If you go about things this way you would probably want to set up the prime detection in a function and then do the same with your number series generator.

That second one though means extending SQL and so I don't know if that fits your requirements.

For postgresql I would use generate_series go generate the list of numbers. I would then create functions which would then either store the list of primes in a temporary table or pass them back in and out in an ordered array and then couple them like that




回答3:


MariaDB (with sequence plugin)

Similar to kordirkos algorithm:

select 2 as p union all
select n.seq
from seq_3_to_1000_step_2 n
where not exists (
    select 1
    from seq_3_to_32_step_2 q
    where q.seq < n.seq
      and n.seq mod q.seq = 0
);

Using LEFT JOIN:

select 2 as p union all
select n.seq
from seq_3_to_1000_step_2 n
left join seq_3_to_32_step_2 q
      on  q.seq < n.seq
      and n.seq mod q.seq = 0
where q.seq is null;

MySQL

There are no sequence generating helpers in MySQL. So the sequence tables have to be created first:

drop temporary table if exists n;
create temporary table if not exists n engine=memory
    select t2.c*100 + t1.c*10 + t0.c + 1 as seq from 
    (select 0 c union all select 1 c union all select 2 c union all select 3 c union all select 4 c union all select 5 c union all select 6 c union all select 7 c union all select 8 c union all select 9 c) t0,
    (select 0 c union all select 1 c union all select 2 c union all select 3 c union all select 4 c union all select 5 c union all select 6 c union all select 7 c union all select 8 c union all select 9 c) t1,
    (select 0 c union all select 1 c union all select 2 c union all select 3 c union all select 4 c union all select 5 c union all select 6 c union all select 7 c union all select 8 c union all select 9 c) t2
    having seq > 2 and seq % 2 != 0;

drop temporary table if exists q;
create temporary table if not exists q engine=memory
    select *
    from n
    where seq <= 32;
alter table q add primary key seq (seq);

Now similar queries can be used:

select 2 as p union all
select n.seq
from n
where not exists (
    select 1
    from q
    where q.seq < n.seq
      and n.seq mod q.seq = 0
);

select 2 as p union all
select n.seq
from n
left join q
    on  q.seq < n.seq
    and n.seq mod q.seq = 0
where q.seq is null;

sqlfiddle




回答4:


Tested on sqlite3

WITH nums(n) AS 
(
    SELECT 1
    UNION ALL
    SELECT n + 1 FROM nums WHERE n < 100
)

SELECT n 
FROM (
  SELECT n FROM nums
) 
WHERE n NOT IN (
  SELECT n
  FROM nums 
  JOIN ( SELECT n AS n2 FROM nums )
  WHERE n  <> 1 
    AND n2 <> 1 
    AND n  <> n2 
    AND n2 <  n 
    AND n % n2 = 0
  ORDER BY n
)
AND n <> 1

Tested on Vertica 8

WITH seq AS (
  SELECT ROW_NUMBER() OVER() AS n 
  FROM (
      SELECT 1 
      FROM (
          SELECT date(0) + INTERVAL '1 second' AS i 
          UNION ALL
          SELECT date(0) + INTERVAL '100 seconds' AS i 
      ) _
      TIMESERIES tm AS '1 second' OVER(ORDER BY i)
  ) _
)
SELECT n 
FROM (SELECT n FROM seq) _  
WHERE n NOT IN (
  SELECT n FROM (
    SELECT s1.n AS n, s2.n AS n2
    FROM seq AS s1 
    CROSS JOIN seq AS s2
    ORDER BY n, n2
  ) _
  WHERE n  <> 1 
    AND n2 <> 1 
    AND n  <> n2 
    AND n2 <  n 
    AND n % n2 = 0
)
AND n <> 1
ORDER BY n



回答5:


Oracle and without inner select in getting part:

 with tmp(id)
as (
    select level  id from dual connect by level <= 100 
) select t1.id from tmp t1
 JOIN tmp t2
 on MOD(t1.id, t2.id) = 0
 group by t1.ID
 having count(t1.id) = 2
 order by t1.ID
 ;



回答6:


MySQL Code :

DECLARE 
@i INT, 
@a INT, 
@count INT, 
@p nvarchar(max)
SET @i = 1 
WHILE (@i <= 1000) 
BEGIN SET @count = 0 
SET @a = 1 
WHILE (@a <= @i) 
BEGIN IF (@i % @a = 0) SET @count = @count + 1 SET @a = @a + 1 
END IF (@count = 2) SET @P = CONCAT(@P,CONCAT(@i,'&')) SET @i = @i + 1 
END
PRINT LEFT(@P, LEN(@P) - 1)



回答7:


The below code works to find prime numbers in SQL

Tested on SampleDB of local server

CREATE procedure sp_PrimeNumber(@number int)
as 
begin
declare @i int
declare @j int
declare @isPrime int
set @isPrime=1
set @i=2
set @j=2
while(@i<=@number)
begin
    while(@j<=@number)
    begin
        if((@i<>@j) and (@i%@j=0))
        begin
            set @isPrime=0
            break
        end
        else
        begin
            set @j=@j+1
        end
    end
    if(@isPrime=1)
    begin
        SELECT @i
    end
    set @isPrime=1
    set @i=@i+1
    set @j=2
end
end

I have created the stored procedure which has a parameter @number to find the prime numbers up to that given number

In order to get the prime numbers we can execute the below stored procedure

EXECUTE sp_PrimeNumber 100  -- gives prime numbers up to 100

If you are new to stored procedures and want to find the prime numbers in SQL we can use the below code

Tested on master DB

declare @i int
declare @j int
declare @isPrime int
set @isPrime=1
set @i=2
set @j=2
while(@i<=100)
begin
    while(@j<=100)
    begin
        if((@i<>@j) and (@i%@j=0))
        begin
            set @isPrime=0
            break
        end
        else
        begin
            set @j=@j+1
        end
    end
    if(@isPrime=1)
    begin
        SELECT @i
    end
    set @isPrime=1
    set @i=@i+1
    set @j=2
end

This code can give the prime numbers between 1 to 100. If we want to find more prime numbers edit the @i and @j arguments in the while loop and execute




回答8:


Simple query in PostgreSQL:

SELECT serA.el AS prime
FROM generate_series(2, 100) serA(el)
LEFT JOIN generate_series(2, 100) serB(el) ON serA.el >= POWER(serB.el, 2)
                                              AND serA.el % serB.el = 0
WHERE serB.el IS NULL

Enjoy! :)




回答9:


For SQL Server We can use below CTE 

SET NOCOUNT ON

;WITH Prim AS
(
    SELECT 2 AS Value 
    UNION ALL
    SELECT t.Value+1 AS VAlue 
    FROM Prim t
    WHERE t.Value < 1000
)SELECT * 
FROM Prim t
WHERE NOT EXISTS(   SELECT 1 FROM prim t2
                WHERE t.Value % t2.Value = 0 
                AND t.Value != t2. Value)
OPTION (MAXRECURSION 0)



回答10:


One simple one can be like this

select level id1 from dual connect by level < 2001
minus
select distinct id1 from (select level id1 from dual connect by level < 46) t1 inner join (select level id2 from dual connect by level < 11) t2
on 1=1 where t1.id1> t2.id2 and mod(id1,id2)=0 and id2<>1



回答11:


Simplest method For SQL Server

DECLARE @range int = 1000, @x INT = 2, @y INT = 2 

While (@y <= @range)
BEGIN
 while (@x <= @y) 
 begin
    IF ((@y%@x) =0) 
    BEGIN
        IF (@x = @y) 
            PRINT @y
            break
    END
 IF ((@y%@x)<>0)   
 set @x = @x+1
 end  
set @x = 2
set @y = @y+1 
end



回答12:


MySQL QUERY SOLUTION

I have solved this problem in mysql which is following:

SET @range = 1000;

SELECT GROUP_CONCAT(R2.n SEPARATOR '&')
FROM (
        SELECT @ctr2:=@ctr2+1 "n"
        FROM information_schema.tables R2IS1,
        information_schema.tables R2IS2,
        (SELECT @ctr2:=1) TI
        WHERE @ctr2<@range
     ) R2
WHERE NOT EXISTS (
                SELECT R1.n
                FROM (
                    SELECT @ctr1:=@ctr1+1 "n"
                    FROM information_schema.tables R1IS1,
                    information_schema.tables R1IS2,
                    (SELECT @ctr1:=1) I1
                    WHERE @ctr1<@range
                ) R1
                WHERE R2.n%R1.n=0 AND R2.n>R1.n
        )

Note: No. of information_schema.tables should be increased for more range e.g. if range is 100000 so set the info tables by checking yourself.



来源:https://stackoverflow.com/questions/37234893/print-prime-numbers-with-sql-query

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