2016-10-03 91 views
2

我有一個整數的表作爲TSQL程序找到的最大素數

number 
-------- 
104723 
104729 
9998 
448 

目的是要找到數字集合中最大的素數。我這樣做有以下程序

Declare @t table(number int) 
Insert into @t values(104723),(104729),(9998),(448) 

Declare @maxNum INT 
SELECT @maxNum = MAX(number) FROM @t 

--generate a number table from 2 to the maximum number supplied 
;WITH Cte AS (
    SELECT 2 AS num 
     UNION ALL 
    SELECT num+1 
    FROM cte 
    WHERE num<@maxNum) 

SELECT TOP(1) num AS 'Largest Prime' FROM cte 
--filter by some known prime numbers (keeping the range between 2 to 19 
WHERE 
    (num=2 OR num%2!=0) AND 
    (num=3 OR num%3!=0) AND 
    (num=5 OR num%5!=0) AND 
    (num=7 OR num%7!=0) AND 
    (num=11 OR num%11!=0) AND 
    (num=13 OR num%13!=0) AND 
    (num=17 OR num%17!=0) AND 
    (num=19 OR num%19!=0) 
ORDER BY 1 DESC 
OPTION (MAXRECURSION 0) 


/* 
Largest Prime 
------------- 
104729 
*/ 

但我相信會有更多更好的方式來做到這一點。請幫助優化相同

+7

T-SQL是一種腳本語言,是這個問題的錯誤選擇。 –

+1

您可以使用這裏定義的SQL'isPrime'函數[SQL素數函數](http://stackoverflow.com/questions/15566619/sql-prime-number-function) –

+2

此腳本沒有找到最大的素數。它發現的最大數小於或等於表中不能被前8個素數整除的最大數。值得注意的是,它a)可以返回原始表中從未出現的值,並且b)不完成評估素數的完整工作。 –

回答

2

我修改了一點點查詢:

DECLARE @t TABLE (number int) 
INSERT INTO @t VALUES 
(104723),(104729),(9998),(448) 

DECLARE @maxNum int 
SELECT @maxNum = MAX(number) 
FROM @t 

;WITH cte AS (
    SELECT 2 AS num 
    UNION ALL 
    SELECT num+1 
    FROM cte 
    WHERE num < @maxNum 
) 

SELECT MAX(number) as LargestPrime 
FROM (
    SELECT number 
    FROM @t t 
    CROSS JOIN Cte c 
    WHERE t.number%c.num=0 
    GROUP BY number 
    HAVING COUNT(num) = 1 
) as t 
OPTION (MAXRECURSION 0) 

這將從@t錶帶來的最大素數:

LargestPrime 
104729 

主要的想法是讓最多的,建立數字從2到最大的CTE。然後進行笛卡爾連接,因此我們可以嘗試從@t和CTE獲得每個數字的modulo。如果有數字的模> 0超過1次 - 它們不是素數。

1

略有不同的方法。

填寫只有素數的表格。

然後只需在質數上加入表格並返回最大值。

declare @T table (number int primary key); 
insert into @T values (104723),(104729),(9998),(448); 

declare @maxNum int; 
set @maxNum = (select max(number) from @T); 

declare @primes TABLE (n int primary key); 
insert into @primes (n) values (2); 

with cte as (
    SELECT 3 AS n 
    UNION ALL 
    SELECT n+2 FROM cte WHERE n+2 <= @maxNum) -- Only uneven numbers lower then @maxNum 
insert into @primes (n) 
select n from cte 
where (n%3 > 0 and n%5 > 0 and n%7 > 0) or n < 8 -- Filter a majority of the non-primes 
option (MAXRECURSION 0); 

-- Remove the numbers where the modulus by a lower number returns 0 
-- Limiting it to the numbers lower or equal to the square root of the number. 
-- The idea behind this is that even if the number has a divisor that's higher than the square root, it would mean there also exists a lower divisor. 
DELETE p FROM @primes p 
WHERE EXISTS (
    SELECT 1 FROM @primes AS p1 
    WHERE p1.n <= CEILING(SQRT(p.n)) and (p.n%p1.n) = 0 and p.n > 8 
); 


select max(t.number) as LargestPrime 
from @T t 
inner join @primes p on (t.number = p.n); 

當然,如果你經常這樣,那麼它可能是值得它來創建一個永久性的表有很多素數。