sexta-feira, 26 de dezembro de 2014

Localizar / analisar uma seqüência de dentro de uma cadeia

Original post: http://anothermysqldba.blogspot.com/2014/12/findparse-string-from-within-string.html

Então, eu notei algumas perguntas diferentes e posts sobre a análise de um seqüência de outra cadeia recentemente. Enquanto algumas soluções incluíram a criação de novas funções e etc, também pode ser realizado dentro de um único comando, em alguns casos. 

Por exemplo, digamos que nós estamos olhando para tirar o domínio de uma URL. Vou tentar entrar em detalhes a respeito de porque e como isso funciona. 
Temos a tabela a seguir. 

CREATE TABLE `parse_example` ( 
`id` int(11) NOT NULL AUTO_INCREMENT, 
`urldemo` varchar(150) NOT NULL, 
PRIMARY KEY (`id`) 
) ENGINE=InnoDB; 
+----+----------------------------+ 
| id | urldemo | 
+----+----------------------------+ 
| 1 | http://www.mysql.com/ | 
| 2 | http://www.percona.com/ | 
| 3 | https://tools.percona.com/ | 
| 4 | https://mariadb.com/ | 
| 5 | http://planet.mysql.com/ | 
| 6 | http://dev.mysql.com/doc/ | 
+----+----------------------------+ 


A meta para este exemplo é desconsiderar o http: // ou https: // e nada depois do .com. Portanto, usar locate para encontrar os locais. 

A referência .com é fácil, uma vez que é constante para que possamos começar com isso. 

SELECT LOCATE('.com', urldemo), urldemo FROM parse_example; 
+-------------------------+----------------------------+ 
| LOCATE('.com', urldemo) | urldemo | 
+-------------------------+----------------------------+ 
| 17 | http://www.mysql.com/ | 
| 19 | http://www.percona.com/ | 
| 22 | https://tools.percona.com/ | 
| 16 | https://mariadb.com/ | 
| 20 | http://planet.mysql.com/ | 
| 17 | http://dev.mysql.com/doc/ | 
+-------------------------+----------------------------+ 


OK assim que nós queremos remover o /, que local é esse? 

SELECT LOCATE('.com', urldemo) as start, LOCATE('.com', urldemo) +4 as end, SUBSTRING(urldemo FROM LOCATE('.com', urldemo) + 4 ) AS resulting , urldemo FROM parse_example; 
+-------+-----+-----------+----------------------------+ 
| start | end | resulting | urldemo | 
+-------+-----+-----------+----------------------------+ 
| 17 | 21 | / | http://www.mysql.com/ | 
| 19 | 23 | / | http://www.percona.com/ | 
| 22 | 26 | / | https://tools.percona.com/ | 
| 16 | 20 | / | https://mariadb.com/ | 
| 20 | 24 | / | http://planet.mysql.com/ | 
| 17 | 21 | /doc/ | http://dev.mysql.com/doc/ | 
+-------+-----+-----------+----------------------------+

Isso nos dá a nossa posição final, eu só colocar os aliases de campo para tornar os resultados mais fáceis de seguir. 

Agora classificando para fora depois de HTTP e HTTPS é realmente muito fácil, bem como ambos têm: // depois deles, por isso, só precisa da localização do segundo / na seqüência. 


SELECT LOCATE('/', urldemo) as first, LOCATE('/', urldemo) +1 as second, urldemo 
FROM parse_example; 
+-------+--------+----------------------------+ 
| first | second | urldemo | 
+-------+--------+----------------------------+ 
| 6 | 7 | http://www.mysql.com/ | 
| 6 | 7 | http://www.percona.com/ | 
| 7 | 8 | https://tools.percona.com/ | 
| 7 | 8 | https://mariadb.com/ | 
| 6 | 7 | http://planet.mysql.com/ | 
| 6 | 7 | http://dev.mysql.com/doc/ | 
+-------+--------+----------------------------+ 


Essas consultas são apenas mostrando o que os diferentes aspectos da consulta final vai fazer. Por isso, vamos colocar tudo isso junto. 


SELECT 
TRIM(TRAILING SUBSTRING(urldemo FROM LOCATE('.com', urldemo) + 4 ) 
FROM SUBSTRING(urldemo FROM LOCATE('/', urldemo) + 2 ) ) AS parsed_domain , 
urldemo as original_url 
FROM parse_example; 
+-------------------+----------------------------+ 
| parsed_domain | original_url | 
+-------------------+----------------------------+ 
| www.mysql.com | http://www.mysql.com/ | 
| www.percona.com | http://www.percona.com/ | 
| tools.percona.com | https://tools.percona.com/ | 
| mariadb.com | https://mariadb.com/ | 
| planet.mysql.com | http://planet.mysql.com/ | 
| dev.mysql.com | http://dev.mysql.com/doc/ | 
+-------------------+----------------------------+ 


Agora espero que o ajuda a ser capaz de analisar o que quer que você precisa. Este exemplo está limitado a um URL. Mas uma vez que alguns exemplos de funções já aqui é o meu exemplo de uma função que você pode usar para analisar o que você precisa. 



CREATE FUNCTION PARSE_STRING(delimiterA VARCHAR(50), delimiterB VARCHAR(50), passed_string VARCHAR(255) ) 
RETURNS VARCHAR(255) DETERMINISTIC 
RETURN 
TRIM(TRAILING SUBSTRING(passed_string FROM LOCATE(delimiterB, passed_string) ) 
FROM SUBSTRING(passed_string FROM LOCATE(delimiterA, passed_string) + CHAR_LENGTH(delimiterA) ) ) ; 

SELECT PARSE_STRING('//','.com', urldemo) FROM parse_example; 
+------------------------------------+ 
| PARSE_STRING('//','.com', urldemo) | 
+------------------------------------+ 
| www.mysql | 
| www.percona | 
| tools.percona | 
| mariadb | 
| planet.mysql | 
| dev.mysql | 
+------------------------------------+ 


Puxe um sobrenome de um campo de nome completo: 

SELECT PARSE_STRING('John ','', 'John Smith') ; 
+----------------------------------------+ 
| PARSE_STRING('John ','', 'John Smith') | 
+----------------------------------------+ 
| Smith | 
+----------------------------------------+ 


Puxe o primeiro nome 

SELECT PARSE_STRING('',' Smith', 'John Smith') ; 
+-----------------------------------------+ 
| PARSE_STRING('',' Smith', 'John Smith') | 
+-----------------------------------------+ 
| John | 
+-----------------------------------------+ 


Concedido com os exemplos de nomes que você precisa saber os valores delimitador. Mas este é apenas um exemplo, você pode construir.

quinta-feira, 18 de dezembro de 2014

Uma partição MySQL e subpartição Exemplo

Original post: http://anothermysqldba.blogspot.com/2014/12/a-mysql-partition-and-subpartition.html

Portanto, este é apenas um exemplo simples de como configurar uma partição e um subpartição em MySQL. O conceito aqui é que você tem dados em uma tabela com vários valores em um campo de data e hora. Você pode ter dados que estão espalhados por vários anos (provavelmente você). Portanto, uma forma de particionar esses dados é classificá-lo por ano, mas, em seguida, também classificá-lo por mês nessa partição anual. 

Abaixo está um exemplo que você pode usar para apreciação. 

Considere a tabela de teste. Sua mesa com ter muitos mais campos de curso. 

CREATE TABLE `t1` ( 
`id` int(11) NOT NULL AUTO_INCREMENT, 
`date_time` datetime DEFAULT NOW(), 
PRIMARY KEY (`id`) 
) ENGINE=InnoDB; 


Primeiro vou preencher a tabela de teste com valores aleatórios para o campo date_time. 

delimiter // 
CREATE PROCEDURE populate_t1( IN rowsofdata INT ) 
BEGIN 

SET @A = 1; 
SET @B = 25 - @A; 

WHILE rowsofdata > 0 DO 
SELECT FLOOR( @A + (RAND() * @B )) INTO @randvalue; 
INSERT INTO t1 
SELECT NULL, NOW() - INTERVAL @randvalue MONTH; 
SET rowsofdata = rowsofdata - 1; 
END WHILE; 
END// 
delimiter ; 
call populate_t1(1000); 


Verifique para ver que tipo de valores que eu acabei com: 

> SELECT COUNT(*) FROM t1 WHERE date_time BETWEEN '2012-01-01 00:00:00' AND '2013-01-01 00:00:00'\G 
*************************** 1. row *************************** 
COUNT(*): 43 
1 row in set (0.00 sec) 

> SELECT COUNT(*) FROM t1 WHERE date_time BETWEEN '2013-01-01 00:00:00' AND '2014-01-01 00:00:00'\G 
*************************** 1. row *************************** 
COUNT(*): 529 
1 row in set (0.00 sec) 

> SELECT COUNT(*) FROM t1 WHERE date_time BETWEEN '2014-01-01 00:00:00' AND NOW() \G
*************************** 1. row *************************** 
COUNT(*): 428 
1 row in set (0.00 sec) 


Agora eu posso alterar a tabela para que eu possa adicionar as minhas partições e depois testar a contagem de valores através da partição. 

ALTER TABLE t1 DROP PRIMARY KEY, ADD PRIMARY KEY (`id`,`date_time`), LOCK=SHARED; 
ALTER TABLE t1 
PARTITION BY RANGE( YEAR(date_time) ) 
SUBPARTITION BY HASH(MONTH(date_time) ) ( 

PARTITION p2012 VALUES LESS THAN (2013) ( 
SUBPARTITION dec_2012, 
SUBPARTITION jan_2012, 
SUBPARTITION feb_2012, 
SUBPARTITION mar_2012, 
SUBPARTITION apr_2012, 
SUBPARTITION may_2012, 
SUBPARTITION jun_2012, 
SUBPARTITION jul_2012, 
SUBPARTITION aug_2012, 
SUBPARTITION sep_2012, 
SUBPARTITION oct_2012, 
SUBPARTITION nov_2012 
), 

PARTITION p2013 VALUES LESS THAN (2014) ( 
SUBPARTITION dec_2013, 
SUBPARTITION jan_2013, 
SUBPARTITION feb_2013, 
SUBPARTITION mar_2013, 
SUBPARTITION apr_2013, 
SUBPARTITION may_2013, 
SUBPARTITION jun_2013, 
SUBPARTITION jul_2013, 
SUBPARTITION aug_2013, 
SUBPARTITION sep_2013, 
SUBPARTITION oct_2013, 
SUBPARTITION nov_2013 

), 
PARTITION p2014 VALUES LESS THAN (2015) ( 
SUBPARTITION dec_2014, 
SUBPARTITION jan_2014, 
SUBPARTITION feb_2014, 
SUBPARTITION mar_2014, 
SUBPARTITION apr_2014, 
SUBPARTITION may_2014, 
SUBPARTITION jun_2014, 
SUBPARTITION jul_2014, 
SUBPARTITION aug_2014, 
SUBPARTITION sep_2014, 
SUBPARTITION oct_2014, 
SUBPARTITION nov_2014 
), 

PARTITION pmax VALUES LESS THAN MAXVALUE ( 
SUBPARTITION dec_max, 
SUBPARTITION jan_max, 
SUBPARTITION feb_max, 
SUBPARTITION mar_max, 
SUBPARTITION apr_max, 
SUBPARTITION may_max, 
SUBPARTITION jun_max, 
SUBPARTITION jul_max, 
SUBPARTITION aug_max, 
SUBPARTITION sep_max, 
SUBPARTITION oct_max, 
SUBPARTITION nov_max 
) 
); 


O meu espectáculo criar a tabela é muito diferente agora. 

> show create table t1; 
CREATE TABLE `t1` ( 
`id` int(11) NOT NULL AUTO_INCREMENT, 
`date_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, 
PRIMARY KEY (`id`,`date_time`) 
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=latin1 
/*!50100 PARTITION BY RANGE ( YEAR(date_time)) 
SUBPARTITION BY HASH (MONTH(date_time)) 
(PARTITION p2012 VALUES LESS THAN (2013) 
(SUBPARTITION dec_2012 ENGINE = InnoDB, 
SUBPARTITION jan_2012 ENGINE = InnoDB, 
SUBPARTITION feb_2012 ENGINE = InnoDB, 
SUBPARTITION mar_2012 ENGINE = InnoDB, 
SUBPARTITION apr_2012 ENGINE = InnoDB, 
SUBPARTITION may_2012 ENGINE = InnoDB, 
SUBPARTITION jun_2012 ENGINE = InnoDB, 
SUBPARTITION jul_2012 ENGINE = InnoDB, 
SUBPARTITION aug_2012 ENGINE = InnoDB, 
SUBPARTITION sep_2012 ENGINE = InnoDB, 
SUBPARTITION oct_2012 ENGINE = InnoDB, 
SUBPARTITION nov_2012 ENGINE = InnoDB), 
PARTITION p2013 VALUES LESS THAN (2014) 
(SUBPARTITION dec_2013 ENGINE = InnoDB, 
SUBPARTITION jan_2013 ENGINE = InnoDB, 
SUBPARTITION feb_2013 ENGINE = InnoDB, 
SUBPARTITION mar_2013 ENGINE = InnoDB, 
SUBPARTITION apr_2013 ENGINE = InnoDB, 
SUBPARTITION may_2013 ENGINE = InnoDB, 
SUBPARTITION jun_2013 ENGINE = InnoDB, 
SUBPARTITION jul_2013 ENGINE = InnoDB, 
SUBPARTITION aug_2013 ENGINE = InnoDB, 
SUBPARTITION sep_2013 ENGINE = InnoDB, 
SUBPARTITION oct_2013 ENGINE = InnoDB, 
SUBPARTITION nov_2013 ENGINE = InnoDB), 
PARTITION p2014 VALUES LESS THAN (2015) 
(SUBPARTITION dec_2014 ENGINE = InnoDB, 
SUBPARTITION jan_2014 ENGINE = InnoDB, 
SUBPARTITION feb_2014 ENGINE = InnoDB, 
SUBPARTITION mar_2014 ENGINE = InnoDB, 
SUBPARTITION apr_2014 ENGINE = InnoDB, 
SUBPARTITION may_2014 ENGINE = InnoDB, 
SUBPARTITION jun_2014 ENGINE = InnoDB, 
SUBPARTITION jul_2014 ENGINE = InnoDB, 
SUBPARTITION aug_2014 ENGINE = InnoDB, 
SUBPARTITION sep_2014 ENGINE = InnoDB, 
SUBPARTITION oct_2014 ENGINE = InnoDB, 
SUBPARTITION nov_2014 ENGINE = InnoDB), 
PARTITION pmax VALUES LESS THAN MAXVALUE 
(SUBPARTITION dec_max ENGINE = InnoDB, 
SUBPARTITION jan_max ENGINE = InnoDB, 
SUBPARTITION feb_max ENGINE = InnoDB, 
SUBPARTITION mar_max ENGINE = InnoDB, 
SUBPARTITION apr_max ENGINE = InnoDB, 
SUBPARTITION may_max ENGINE = InnoDB, 
SUBPARTITION jun_max ENGINE = InnoDB, 
SUBPARTITION jul_max ENGINE = InnoDB, 
SUBPARTITION aug_max ENGINE = InnoDB, 
SUBPARTITION sep_max ENGINE = InnoDB, 
SUBPARTITION oct_max ENGINE = InnoDB, 
SUBPARTITION nov_max ENGINE = InnoDB)) 


Então, podemos ainda contar com o nosso valor como esperado? 

> SELECT count(*) FROM t1 PARTITION (p2012) \G 
*************************** 1. row *************************** 
count(*): 43 
> SELECT count(*) FROM t1 PARTITION (p2013) \G 
*************************** 1. row *************************** 
count(*): 529 
> SELECT count(*) FROM t1 PARTITION (p2014) \G 
*************************** 1. row *************************** 
count(*): 428 


Até aí tudo bem, todos os valores combinados até a contagem que tínhamos antes. Por isso, também pode contar ou selecione per da subpartição. 


> SELECT * FROM t1 PARTITION (dec_2012) limit 5; 
+-----+---------------------+ 
| id | date_time | 
+-----+---------------------+ 
| 59 | 2012-12-19 00:59:57 | 
| 68 | 2012-12-19 00:59:58 | 
| 93 | 2012-12-19 00:59:59 | 
| 105 | 2012-12-19 00:59:59 | 
| 111 | 2012-12-19 00:59:59 | 
+-----+---------------------+ 

> SELECT * FROM t1 PARTITION (jan_2013) limit 5; 
+-----+---------------------+ 
| id | date_time | 
+-----+---------------------+ 
| 6 | 2013-01-19 00:59:55 | 
| 29 | 2013-01-19 00:59:56 | 
| 55 | 2013-01-19 00:59:57 | 
| 79 | 2013-01-19 00:59:58 | 
| 100 | 2013-01-19 00:59:59 | 
+-----+---------------------+ 

> SELECT * FROM t1 PARTITION (jan_2014) limit 5; 
+-----+---------------------+ 
| id | date_time | 
+-----+---------------------+ 
| 16 | 2014-01-19 00:59:55 | 
| 190 | 2014-01-19 01:00:04 | 
| 191 | 2014-01-19 01:00:04 | 
| 229 | 2014-01-19 01:00:05 | 
| 234 | 2014-01-19 01:00:06 | 
+-----+---------------------+ 

> SELECT * FROM t1 PARTITION (jun_2014) limit 5; 
+-----+---------------------+ 
| id | date_time | 
+-----+---------------------+ 
| 13 | 2014-06-19 00:59:55 | 
| 189 | 2014-06-19 01:00:04 | 
| 221 | 2014-06-19 01:00:05 | 
| 222 | 2014-06-19 01:00:05 | 
| 238 | 2014-06-19 01:00:06 | 
+-----+---------------------+ 

> SELECT * FROM t1 PARTITION (dec_2013) limit 5; 
+-----+---------------------+ 
| id | date_time | 
+-----+---------------------+ 
| 50 | 2013-12-19 00:59:57 | 
| 74 | 2013-12-19 00:59:58 | 
| 98 | 2013-12-19 00:59:59 | 
| 107 | 2013-12-19 00:59:59 | 
| 167 | 2013-12-19 01:00:02 | 
+-----+---------------------+ 


Isso é ótimo e útil, mas o que acontece quando o ano de 2015 ou 2016 vem por aí? Todos os dados de que seria na partição pmax. Então, como vamos adicionar uma nova partição entre P2014 e Pmax? 

Se você não tinha dados em pmax você poderia largá-lo e adicionar uma nova partição para o final. Mas é tão fácil de reorganizar a partição. Isso levará a partição pmax e alterá-lo em nossas novas partições. 


ALTER TABLE t1 REORGANIZE PARTITION pmax INTO ( 
PARTITION p2015 VALUES LESS THAN (2016) ( 
SUBPARTITION dec_2015, 
SUBPARTITION jan_2015, 
SUBPARTITION feb_2015, 
SUBPARTITION mar_2015, 
SUBPARTITION apr_2015, 
SUBPARTITION may_2015, 
SUBPARTITION jun_2015, 
SUBPARTITION jul_2015, 
SUBPARTITION aug_2015, 
SUBPARTITION sep_2015, 
SUBPARTITION oct_2015, 
SUBPARTITION nov_2015 
), 
PARTITION pmax VALUES LESS THAN MAXVALUE ( 
SUBPARTITION dec_max, 
SUBPARTITION jan_max, 
SUBPARTITION feb_max, 
SUBPARTITION mar_max, 
SUBPARTITION apr_max, 
SUBPARTITION may_max, 
SUBPARTITION jun_max, 
SUBPARTITION jul_max, 
SUBPARTITION aug_max, 
SUBPARTITION sep_max, 
SUBPARTITION oct_max, 
SUBPARTITION nov_max 
) 
); 


Espero que isso ajude, boa sorte.