有条件地解析mysql select中的字符串

有条件地解析mysql select中的字符串,mysql,Mysql,我试图使DNS区域传输在绑定DLZ环境中工作,并为动态加载的区域提供mysql支持。不管是谁(我猜是在2013年9月3日)最初设置了这个系统,他都做得很懒。因为像serial和expire这样的字段只在SOA记录中使用,所以所有这些字段的值都被固定在一个带有空格的字段中。这适用于普通DNS使用,但不适用于区域传输 mysql> SELECT `data` FROM `bind` WHERE `zone`='example.com' AND `type`='SOA'; +----------

我试图使DNS区域传输在绑定DLZ环境中工作,并为动态加载的区域提供mysql支持。不管是谁(我猜是在2013年9月3日)最初设置了这个系统,他都做得很懒。因为像serial和expire这样的字段只在SOA记录中使用,所以所有这些字段的值都被固定在一个带有空格的字段中。这适用于普通DNS使用,但不适用于区域传输

mysql> SELECT `data` FROM `bind` WHERE `zone`='example.com' AND `type`='SOA';
+---------------------------------------------------------------------------------+
| data                                                                            |
+---------------------------------------------------------------------------------+
| core-dns-01.example.com. sysadmin.example.com. 2013090337 86400 3600 86400 3600 |
+---------------------------------------------------------------------------------+
1 row in set (0.00 sec)
对于区域传输查询,根据,我需要将它们作为单独的值

我已经做到了:

SELECT `ttl`, `type`, `host`, `mx_priority`
   ,SUBSTRING_INDEX(                 `data`, ' ', 1)           AS `data`
   ,SUBSTRING_INDEX( SUBSTRING_INDEX(`data`, ' ', 2), ' ', -1) AS `resp_person`
   ,SUBSTRING_INDEX( SUBSTRING_INDEX(`data`, ' ', 3), ' ', -1) AS `serial`
   ,SUBSTRING_INDEX( SUBSTRING_INDEX(`data`, ' ', 4), ' ', -1) AS `refresh`
   ,SUBSTRING_INDEX( SUBSTRING_INDEX(`data`, ' ', 5), ' ', -1) AS `retry`
   ,SUBSTRING_INDEX( SUBSTRING_INDEX(`data`, ' ', 6), ' ', -1) AS `expire`
   ,SUBSTRING_INDEX( SUBSTRING_INDEX(`data`, ' ', 7), ' ', -1) AS `minimum`
FROM `bind` WHERE `zone`='%zone%'
              AND `type`='SOA';
(请注意,
%zone%
是绑定DLZ以替换查询值的专用工具;它不是通配符匹配。)

但是,当我使用正确的查询
时,这会非常失败,其中zone='%zone%'和(type='SOA'或type='NS')
,因为NS记录中只有一个值,应该作为
数据返回

在这里,我已经达到了SQL诀窍的极限。我真的不知道如何(甚至不知道是否)进行一个查询,返回一个已解析的SOA和一组未解析的NS记录(对于缺少的值,
NULL
)。能做到吗?怎么做

方法1

在分号之前添加以下语句。并集将第二个select的行添加到firest后面

Union 
SELECT `ttl`, `type`, `host`, NULL AS `mx_priority`
, `data`          AS `data`
,NULL AS `resp_person`
,NULL AS `serial`
,NULL AS `refresh`
,NULL AS `retry`
,NULL AS `expire`
,NULL AS `minimum`
FROM `bind` WHERE `zone`='%zone%'
          AND `type`='NS'
这将根据以下内容提供所有NS记录:

ttl = 3600
type = NS
host = @
data = NS1
all other fields in the row are NULL.
方法2

正如您所看到的,您可以检查任何列是否是SOA或NS,并处理所需的结果。如果有两个以上的条件,则可以切换到CASE-WHEN或嵌套IFs

SELECT `ttl`, `type`, `host`
 , IF(type='SOA',`mx_priority`,NULL) AS `mx_priority`
 ,IF(type='SOA',SUBSTRING_INDEX(                 `data`, ' ', 1),`data`) AS `data`
 ,IF(type='SOA',SUBSTRING_INDEX( SUBSTRING_INDEX(`data`, ' ', 2), ' ', 
   -1),NULL) AS `resp_person`
 ,IF(type='SOA',SUBSTRING_INDEX( SUBSTRING_INDEX(`data`, ' ', 3), ' ',
    -1),NULL) AS `serial`
 ,IF(type='SOA',SUBSTRING_INDEX( SUBSTRING_INDEX(`data`, ' ', 4), ' ',
    -1),NULL) AS `refresh`
 ,IF(type='SOA',SUBSTRING_INDEX( SUBSTRING_INDEX(`data`, ' ', 5), ' ',
    -1),NULL) AS `retry`
 ,IF(type='SOA',SUBSTRING_INDEX( SUBSTRING_INDEX(`data`, ' ', 6), ' ',
   -1),NULL) AS `expire`
 ,IF(type='SOA',SUBSTRING_INDEX( SUBSTRING_INDEX(`data`, ' ', 7), ' ',
    -1),NULL) AS `minimum`
 FROM `bind` WHERE `zone``zone`='%zone%'
          AND (type='SOA' or `type`='NS' )

您的意思是
zone='%zone%'
进行通配符匹配吗?为此,您需要使用类似“%zone%”的
区域。
=
运算符只匹配文本字符串。绑定DLZ将用查询的实际区域替换“%zone%”。我更新了问题以澄清问题。除了语法错误(例如“
type
host
”),这两种方法看起来都不错。谢谢。我说错了,SOA和NS记录需要主机。我用
选择ttl,type,mx_priority,IF(type='SOA',SUBSTRING_INDEX(data',,1),data)作为数据,IF(type='SOA',SUBSTRING_INDEX(SUBSTRING_INDEX(data',,2),'','-1),NULL)作为resp_person,[…]IF(type='SOA',SUBSTRING_INDEX(SUBSTRING_INDEX(data',,7),'-1),NULL)作为绑定的最小值,其中zone='%zone%'和(type='SOA'或type='NS')
。此数据库具有
mx\u优先级
,因此无需伪造该优先级。