[英]Print Prime Numbers with SQL query
我是 StackOverflow 的新手,並且遇到了一個打印從 2 到 1000 的素數的查詢。如果這是最有效的編碼方式,我已經使用了下面的查詢需要輸入。
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;
我知道這個問題已被多次問過,如果有的話,我要求更好的解決方案。 更多關於它如何與 MySQL/MS SQL/PostgreSQL 一起工作的需要輸入。
任何幫助都會使我更好地理解。
在 PostgreSQL 中,打印最多 1000 個素數的最快查詢可能是:
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
;
在我的電腦上只用了 16 毫秒。
如果您更喜歡 SQL,那么這行得通
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
)
;
它慢了兩倍 - 31 毫秒。
回答 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
)
;
SELECT GROUP_CONCAT(NUMB SEPARATOR '&')
FROM (
SELECT @num:=@num+1 as NUMB FROM
information_schema.tables t1,
information_schema.tables t2,
(SELECT @num:=1) tmp
) tempNum
WHERE NUMB<=1000 AND NOT EXISTS(
SELECT * FROM (
SELECT @nu:=@nu+1 as NUMA FROM
information_schema.tables t1,
information_schema.tables t2,
(SELECT @nu:=1) tmp1
LIMIT 1000
) tatata
WHERE FLOOR(NUMB/NUMA)=(NUMB/NUMA) AND NUMA<NUMB AND NUMA>1
)
最明顯的改進是,您可以檢查從 1 到 n 的平方根,而不是檢查從 1 到 n。
第二個主要優化是使用臨時表來存儲結果並首先檢查它們。 這樣你可以從 1 到 n 遞增迭代,並且只檢查從 1 到 n 的平方根的已知素數(遞歸地這樣做,直到你有一個列表)。 如果您以這種方式進行操作,您可能希望在函數中設置素數檢測,然后對您的數列生成器執行相同的操作。
第二個雖然意味着擴展 SQL,所以我不知道這是否符合您的要求。
對於 postgresql,我將使用generate_series
生成數字列表。 然后我將創建函數,然后將素數列表存儲在臨時表中,或者將它們傳入和傳出有序數組,然后像這樣耦合它們
MariaDB(帶有序列插件)
類似於 kordirkos 算法:
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
);
使用左連接:
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
MySQL 中沒有序列生成助手。 所以必須先創建序列表:
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);
現在可以使用類似的查詢:
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;
Oracle 並且在獲取部分時沒有內部選擇:
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
;
/* Below is my solution */
/* Step 1: Get all the numbers till 1000 */
with tempa as
(
select level as Num
from dual
connect by level<=1000
),
/* Step 2: Get the Numbers for finding out the factors */
tempb as
(
select a.NUm,b.Num as Num_1
from tempa a , tempa b
where b.Num<=a.Num
),
/*Step 3:If a number has exactly 2 factors, then it is a prime number */
tempc as
(
select Num, sum(case when mod(num,num_1)=0 then 1 end) as Factor_COunt
from tempb
group by Num
)
select listagg(Num,'&') within group (order by Num)
from tempc
where Factor_COunt=2
;
在 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
在 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
這就是在 SQL 服務器中對我有用的方法。 我試圖減少嵌套循環的順序。
declare @var int
declare @i int
declare @result varchar (max)
set @var = 1
select @result = '2&3&5' --first few obvious prime numbers
while @var < 1000 --the first loop
begin
set @i = 3;
while @i <= @var/2 --the second loop which I attempted to reduce the order
begin
if @var%@i = 0
break;
if @i=@var/2
begin
set @result = @result + '&' + CAST(@var AS VARCHAR)
break;
end
else
set @i = @i + 1
end
set @var = @var + 1;
end
print @result
SELECT LISTAGG(PRIME_NUMBER,'&') WITHIN GROUP (ORDER BY PRIME_NUMBER)
FROM
(
SELECT L PRIME_NUMBER FROM
(
SELECT LEVEL L FROM DUAL CONNECT BY LEVEL <= 1000 ),
(
SELECT LEVEL M FROM DUAL CONNECT BY LEVEL <= 1000
) WHERE M <= L
GROUP BY L
HAVING COUNT(CASE WHEN L/M = TRUNC(L/M) THEN 'Y' END
) = 2
ORDER BY L
);
MySQL 代碼:
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)
下面的代碼用於在 SQL 中查找素數
在本地服務器的 SampleDB 上測試
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
我創建了一個存儲過程,它有一個參數 @number 來查找到給定數字的素數
為了得到素數,我們可以執行下面的存儲過程
EXECUTE sp_PrimeNumber 100 -- gives prime numbers up to 100
如果您不熟悉存儲過程並想在 SQL 中查找素數,我們可以使用以下代碼
在主數據庫上測試
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
這段代碼可以給出 1 到 100 之間的素數。如果我們想找到更多的素數,請在 while 循環中編輯 @i 和 @j 參數並執行
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
享受! :)
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)
一個簡單的可以是這樣的
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
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
我已經在mysql中解決了這個問題,如下:
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
)
注意:應該增加information_schema.tables的數量以獲得更大的范圍,例如,如果范圍是 100000,那么通過檢查自己來設置信息表。
--Create Table prime_number_t create table prime_number_t ( integervalue_c integer not null primary key );
--Insert Data into table prime_number_t INSERT ALL into prime_number_t(integervalue_c) values (1) into prime_number_t(integervalue_c) values (2) into prime_number_t(integervalue_c) values (3) into prime_number_t(integervalue_c) values (4) into prime_number_t(integervalue_c)值 (5) 轉化為 prime_number_t(integervalue_c) 值 (6) 轉化為 prime_number_t(integervalue_c) 值 (7) 轉化為 prime_number_t(integervalue_c) 值 (8) 轉化為 prime_number_t(integervalue_c) 值 (9) 轉化為 prime_number_t(integervalue_c) 值 (10)
從雙重中選擇 1;
犯罪;
-- 編寫一條 SQL 語句來確定以下哪些數字是素數 -- 相同的查詢也適用於 REMAINDER 函數,而不是 MOD 函數 WITH cte_prime_number_t AS ( select integervalue_c from prime_number_t order by integervalue_c ), cte_maxval AS ( select max(integervalue_c) AS maxval FROM cte_prime_number_t ), cte_level AS ( 選擇 LEVEL+1 作為 lvl from dual, cte_maxval CONNECT BY LEVEL <= cte_maxval.maxval ) SELECT DISTINCT cpnt.integervalue_c 作為 PrimeNumbers FROM cte_prime_number_t cpnt 內連接 cte_level cl on lvl <= (SELECT maxval FROM cte_maxval) WHERE NOT EXISTS (SELECT 1 FROM cte_level cpn WHERE cpnt.integervalue_c > cpn.lvl AND mod(cpnt.integervalue_c,cpn.lvl) = 0) 按 PrimeNumbers 排序;
這在 MySql 中對我有用:
select '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';
好吧,我知道上面的代碼只是硬編碼的,你可以運行這個問題,但這不是我們作為程序員應該追求的,所以這是我對 oracle 的解決方案:
SELECT LISTAGG(L1,'&') WITHIN GROUP (ORDER BY L1) FROM (Select L1 FROM (SELECT LEVEL L1 FROM DUAL CONNECT BY LEVEL<=1000) Where L1 <> 1 MINUS select L1 from (SELECT LEVEL L1 FROM DUAL CONNECT BY LEVEL<=1000) A , (SELECT LEVEL L2 FROM DUAL CONNECT BY LEVEL<=1000) B Where L2<=L1 and MOD(L1,L2)=0 AND L1<>L2 AND L2<>1);
MySQL 8 或更高版本
/* create a table with one row and that starts with 2 ends at 1000*/
SET cte_max_recursion_depth = 1001; /* works for MySQL 8.0*/
;WITH RECURSIVE sequence AS (
SELECT 1 AS l
UNION ALL
SELECT l + 1 AS value
FROM sequence
WHERE sequence.l < 1000
),
/* create a caretesian product of a number to other numbers uptil this very number
so for example if there is a value 5 in a row then it creates these rows using the table below
(5,2), (5,3), (5,4), (5,5) */
J as (
SELECT (a.l) as m , (b.l) as n
FROM sequence a, sequence b
WHERE b.l <= a.l)
,
/*take a row from column 1 then divide it with other column values but group by column 1 first,
note the completely divisible count*/
f as
( SELECT m , SUM(CASE WHEN mod(m,n) = 0 THEN 1 END) as fact
FROM J
GROUP BY m
HAVING fact = 2
ORDER BY m ASC /*this view return numbers in descending order so had to use order by*/
)
/* this is for string formatting, converting a column to a string with separator &*/
SELECT group_concat(m SEPARATOR '&') FROM f;
在甲骨文工作過:
SELECT LISTAGG(a,'&')
WITHIN GROUP (ORDER BY a)
FROM(WITH x AS(
SELECT level+1 x
FROM dual
CONNECT BY LEVEL <= 999
)
SELECT x.x as a
FROM x
WHERE NOT EXISTS (
SELECT 1 FROM x y
WHERE x.x > y.x AND remainder( x.x, y.x) = 0
));
SELECT GROUP_CONCAT(distinct PRIME_NUMBER SEPARATOR '&')
FROM (SELECT @prime:=@prime + 1 AS PRIME_NUMBER
FROM information_schema.tables
CROSS JOIN (SELECT @prime:=1) r
WHERE @num <1000
) p
WHERE NOT EXISTS (
SELECT * FROM
(SELECT @divisor := @divisor + 1 AS DIVISOR FROM
information_schema.tables
CROSS JOIN (SELECT @divisor:=1) r1
WHERE @divisor <=1000
) d
WHERE MOD(PRIME_NUMBER, DIVISOR) = 0 AND PRIME_NUMBER != DIVISOR) ;
enter code here
解釋:
兩個內部 SELECT(SELECT @prime 和 SELECT @divisor)創建兩個列表。 它們都包含從 1 到 1000 的數字。第一個列表是“潛在素數列表”,第二個是“除數列表”
然后,我們遍歷潛在素數列表(外部 SELECT),並為該列表中的每個數字尋找除數(SELECT * FROM 子句),它可以在沒有提示的情況下除數並且不等於數字( WHERE MOD... 子句)。 如果至少存在一個這樣的除數,則該數字不是素數並且未被選中(WHERE NOT EXISTS... 子句)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.