2008-11-10 13 views
11

के सिडर मान को निर्धारित करने के लिए एसक्यूएल का उपयोग करना मैं SQL क्वेरी करने का एक तरीका ढूंढना चाहता हूं जो डेटाबेस में संग्रहीत एक सबनेट मास्क के सिडर (बिट प्रतिनिधित्व) की गणना करेगा। तो उदाहरण के लिए, मुझे डेटाबेस में संग्रहीत 255.255.255.0 या उसके दशमलव मान (42 9 4 9 67040) मिला है। मैं एक चयन करना चाहता हूं और क्वेरी के माध्यम से वापस/24 प्रतिनिधित्व प्राप्त करना चाहता हूं।एक सबनेट मास्क

मैंने सबनेट की अंतिम आईपी निर्धारित करने के लिए निम्न की तरह चीजें की हैं, इसलिए मैं मास्क के सिडर प्रतिनिधित्व को निर्धारित करने के लिए कुछ ऐसा करने की उम्मीद कर रहा हूं।

select concat(inet_ntoa(ip_addr),'-', 
    inet_ntoa(ip_addr+(POWER(2,32)-ip_mask-1))) range 
from subnets 
order by ip_addr 

अधिमानतः यह एक एसक्यूएल बयान है कि mysql, postgres, ओरेकल आदि के तहत काम होगा

उत्तर

8

मुझे लगता है कि मुझे अपने मुद्दे का समाधान मिला है। यहां मैंने जो किया है:

select CONCAT(INET_NTOA(ip_addr),'/',32-log2((4294967296-ip_mask))) net 
from subnets 
order by ip_addr 

असल में मैं अपना decmial मुखौटा लेता हूं और इसे अधिकतम दशमलव मान से घटा देता हूं। मैं फिर लॉगरिदम मूल्य प्राप्त करने के लिए उस मान पर लॉग 2 पर हूं। फिर बस 32 से घटाएं (अधिकतम बिट उपलब्ध)।

आशा है कि दूसरों की मदद करें।

धन्यवाद

+0

log2 ... कमाल! :-) –

+0

मैंने इस तालिका में सभी मानों के विरुद्ध यह जांच की और इसे सटीक पाया: https://kthx.at/subnetmask/। – apostl3pol

2

एसक्यूएल प्रश्नों एक प्रक्रियात्मक पाशन निर्माण (प्रक्रियात्मक भाषा के होते हुए भी) की जरूरत नहीं है, लेकिन आप एक तुलना कर सकते हैं पंक्तियों का एक और सेट पंक्तियों का सेट, जो एक लूप की तरह है।

आपके पास केवल 32 संभव सबनेट मास्क हैं। इस तरह के मामलों में, यह एक छोटी सी टेबल बनाने के लिए समझ में आता है जो इन 32 मास्क और संबंधित सीआईडीआर नंबर को स्टोर करता है।

CREATE TABLE cidr (
    bits INT UNSIGNED PRIMARY KEY, 
    mask INT UNSIGNED NOT NULL 
); 

INSERT INTO cidr (bits) VALUES 
    (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), 
    (11), (12), (13), (14), (15), (16), (17), (18), (19), (20), 
    (21), (22), (23), (24), (25), (26), (27), (28), (29), (30), 
    (31), (32); 

UPDATE cidr SET mask = ((POWER(2,32)-1)<<(32-bits)) & (POWER(2,32)-1); 

SELECT CONCAT(s.ip_addr, '/', c.bits) 
FROM cidr c JOIN subnets s ON (c.mask = inet_aton(s.ip_mask)); 
+0

जोड़ा जा रहा है एक मेज था कि मैं क्या करने के लिए आशा व्यक्त की थी से बचें। मैं आशा करता था कि आगे गणितीय गणनाएं होंगी जो दशमलव से बाइनरी में परिवर्तित करने के लिए की जा सकती हैं, फिर बिट्स की गणना करें। धन्यवाद हालांकि, यह उपयोगी था –

0
-- 
-- Dumping routines for database 
-- 
/*!50003 DROP FUNCTION IF EXISTS `INET_ATOC` */; 
/*!50003 SET @saved_cs_client  = @@character_set_client */ ; 
/*!50003 SET @saved_cs_results  = @@character_set_results */ ; 
/*!50003 SET @saved_col_connection = @@collation_connection */ ; 
/*!50003 SET character_set_client = utf8 */ ; 
/*!50003 SET character_set_results = utf8 */ ; 
/*!50003 SET collation_connection = utf8_general_ci */ ; 
/*!50003 SET @saved_sql_mode  = @@sql_mode */ ; 
/*!50003 SET sql_mode    = 'ALLOW_INVALID_DATES' */ ; 
DELIMITER ;; 
CREATE DEFINER=`root`@`localhost` FUNCTION `INET_ATOC`(`paramNETMASK` varchar(15)) RETURNS int(2) unsigned 
    DETERMINISTIC 
    COMMENT 'Converts an IPv4 netmask in dotted decimal notation to a CIDR integer between 0 and 32' 
BEGIN 
    DECLARE `netmask` int unsigned; 
    DECLARE `cidr` int unsigned; 
    SET `netmask` = INET_ATON(`paramNETMASK`); 
    IF (`netmask` IS NULL) 
    THEN 
     RETURN NULL; 
    ELSE 
     SET `cidr` = 0; 
     countNetBits: WHILE (`cidr` < 32) 
     DO 
      IF ((0x80000000 & `netmask`) = 0x80000000) 
      THEN 
       SET `netmask` = 0xFFFFFFFF & (`netmask` << 1); 
       SET `cidr` = `cidr` + 1; 
      ELSE 
       LEAVE countNetBits; 
      END IF; 
     END WHILE; 
     IF (`netmask` != 0) 
     THEN 
      RETURN NULL; 
     END IF; 
     RETURN `cidr`; 
    END IF; 
END ;; 
DELIMITER ; 
/*!50003 SET sql_mode    = @saved_sql_mode */ ; 
/*!50003 SET character_set_client = @saved_cs_client */ ; 
/*!50003 SET character_set_results = @saved_cs_results */ ; 
/*!50003 SET collation_connection = @saved_col_connection */ ; 
/*!50003 DROP FUNCTION IF EXISTS `INET_CTOA` */; 
/*!50003 SET @saved_cs_client  = @@character_set_client */ ; 
/*!50003 SET @saved_cs_results  = @@character_set_results */ ; 
/*!50003 SET @saved_col_connection = @@collation_connection */ ; 
/*!50003 SET character_set_client = utf8 */ ; 
/*!50003 SET character_set_results = utf8 */ ; 
/*!50003 SET collation_connection = utf8_general_ci */ ; 
/*!50003 SET @saved_sql_mode  = @@sql_mode */ ; 
/*!50003 SET sql_mode    = 'ALLOW_INVALID_DATES' */ ; 
DELIMITER ;; 
CREATE DEFINER=`root`@`localhost` FUNCTION `INET_CTOA`(`paramCIDR` int) RETURNS varchar(15) CHARSET utf8 
    DETERMINISTIC 
    COMMENT 'Converts a CIDR suffix (integer between 0 and 32) to an IPv4 netmask in dotted decimal notation' 
BEGIN 
    DECLARE `netmask` int unsigned; 
    IF ((`paramCIDR` < 0) OR (`paramCIDR` > 32)) 
    THEN 
     RETURN NULL; 
    ELSE 
     SET `netmask` = 0xFFFFFFFF - (pow(2, (32-`paramCIDR`)) - 1); 
     RETURN INET_NTOA(`netmask`); 
    END IF; 
END ;; 
DELIMITER ; 
/*!50003 SET sql_mode    = @saved_sql_mode */ ; 
/*!50003 SET character_set_client = @saved_cs_client */ ; 
/*!50003 SET character_set_results = @saved_cs_results */ ; 
/*!50003 SET collation_connection = @saved_col_connection */ ; 
/*!50003 DROP PROCEDURE IF EXISTS `getSubnet` */; 
/*!50003 SET @saved_cs_client  = @@character_set_client */ ; 
/*!50003 SET @saved_cs_results  = @@character_set_results */ ; 
/*!50003 SET @saved_col_connection = @@collation_connection */ ; 
/*!50003 SET character_set_client = utf8 */ ; 
/*!50003 SET character_set_results = utf8 */ ; 
/*!50003 SET collation_connection = utf8_general_ci */ ; 
/*!50003 SET @saved_sql_mode  = @@sql_mode */ ; 
/*!50003 SET sql_mode    = '' */ ; 
DELIMITER ;; 
CREATE DEFINER=`root`@`localhost` PROCEDURE `getSubnet`(INOUT `paramADDR` VARCHAR(15), INOUT `paramCIDR` INT, OUT `paramMASK` VARCHAR(15), OUT `paramNETWORK` VARCHAR(15), OUT `paramBROADCAST` VARCHAR(15), OUT `paramNUMHOSTS` INT) CHARSET utf8 
    DETERMINISTIC 
BEGIN 
    DECLARE `numaddrs` int unsigned; 
    DECLARE `ipaddr` int unsigned; 
    DECLARE `netmask` int unsigned; 
    DECLARE `wildcard` int unsigned; 
    DECLARE `network` int unsigned; 
    DECLARE `broadcast` int unsigned; 
    DECLARE `numhosts` int unsigned; 

    SET `ipaddr` = INET_ATON(`paramADDR`); 

    IF (`ipaddr` IS NULL) OR (`paramCIDR` < 1) OR (`paramCIDR` > 30) 
    THEN 
     SELECT 
      NULL, NULL, NULL, NULL, NULL, NULL 
     INTO 
      `paramADDR`, `paramCIDR`, `paramMASK`, `paramNETWORK`, `paramBROADCAST`, `paramNUMHOSTS`; 
    ELSE 
     SET `numaddrs` = pow(2, (32-`paramCIDR`)); 
     SET `numhosts` = `numaddrs` - 2; 
     SET `netmask` = 0xFFFFFFFF - (`numaddrs` - 1); 
     SET `wildcard` = 0xFFFFFFFF & (~`netmask`); 
     SET `network` = `ipaddr` & `netmask`; 
     SET `broadcast` = `ipaddr` | `wildcard`; 

     SELECT 
      INET_NTOA(`ipaddr`), `paramCIDR`, INET_NTOA(`netmask`), INET_NTOA(`network`), INET_NTOA(`broadcast`), `numhosts` 
     INTO 
      `paramADDR`, `paramCIDR`, `paramMASK`, `paramNETWORK`, `paramBROADCAST`, `paramNUMHOSTS`; 
    END IF; 
END ;; 
DELIMITER ; 
/*!50003 SET sql_mode    = @saved_sql_mode */ ; 
/*!50003 SET character_set_client = @saved_cs_client */ ; 
/*!50003 SET character_set_results = @saved_cs_results */ ; 
/*!50003 SET collation_connection = @saved_col_connection */ ; 
/*!40103 SET [email protected]_TIME_ZONE */; 

/*!40101 SET [email protected]_SQL_MODE */; 
/*!40014 SET [email protected]_FOREIGN_KEY_CHECKS */; 
/*!40014 SET [email protected]_UNIQUE_CHECKS */; 
/*!40101 SET C[email protected]_CHARACTER_SET_CLIENT */; 
/*!40101 SET [email protected]_CHARACTER_SET_RESULTS */; 
/*!40101 SET [email protected]_COLLATION_CONNECTION */; 
/*!40111 SET [email protected]_SQL_NOTES */; 
0

उदा आपको 255.255.255.252 नेटमास्क को बिट मास्क में कनवर्ट करने की आवश्यकता है।

मैं हमेशा इस सरल प्रश्न (PostgreSQL) का उपयोग करें:

SELECT 32-length(trim(((split_part('255.255.255.252','.',1)::bigint*(256^3)::bigint + 
         split_part('255.255.255.252','.',2)::bigint*(256^2)::bigint + 
         split_part('255.255.255.252','.',3)::bigint*256 + 
         split_part('255.255.255.252','.',4)::bigint)::bit(32))::text,'1')); 

के रूप में हो सकता है के रूप में अच्छा नहीं है, लेकिन यह कम है और एक आकर्षण की तरह काम कर रहा है ..

संबंधित मुद्दे