Desafio Tabuada em TSQL

Comecei alguns desafios com a equipe de banco da empresa pedindo algumas soluções para um problema…

Semana passada eles tinham que entregar um código que mostra-se uma tabuada… mas haviam algumas premissas:

  1. Eu poderia escolher de qual a qual número. Ex.: tabuada do 2 ao 10 ou do 5 ao 20…
  2. em todos os casos o resultado deveria ser um texto que possuísse o símbolo de multiplicação X e o sinal de igual =…

O pessoal se empenhou e vieram com códigos interessantes…

um deles foi:

DECLARE @InicNum int, @FimcNum int
SET @InicNum = 5
SET @FimcNum = 7
;WITH numeros AS (
 SELECT number AS N
 FROM master..spt_values
 WHERE type = 'P'
 AND number BETWEEN CAST(@InicNum AS varchar) AND CAST(@FimcNum AS varchar)
),
F1 AS(
select number as N from spt_values
where type = 'P'
AND number BETWEEN 1 AND 10
),
produto AS (
 SELECT
 M = n2.N,
 F = n1.N,
 P = n1.N * n2.N
 FROM F1 n1
 CROSS JOIN numeros n2
)
SELECT cast(M as varchar(2)) + ' x ' + cast(F as varchar(2)) + ' = ' + cast(P as varchar(3))
FROM produto
order by M

outra opção:

DECLARE @CALC1 INT, @CALC2 INT
DECLARE @NUM1 VARCHAR(500), @NUM2 VARCHAR(500) , @RESTO VARCHAR(500), @LINHA NVARCHAR(500)
SET @CALC1 = 1
WHILE @CALC1 <= 10 -- AQUI

BEGIN
 SET @LINHA = @CALC1
 SELECT '" TABUADA DO ' + CONVERT(VARCHAR(15),@LINHA) + ' "'
 SET @CALC2 = 1
 WHILE @CALC2 <= 10 --
 BEGIN
 SET @NUM1 = @CALC1
 SET @NUM2 = @CALC2
 SET @RESTO = @CALC1 * @CALC2
 SELECT @NUM1 + 'X' + @NUM2 + ' = ' + @RESTO AS 'TABUDA'
 SET @CALC2 = @CALC2 + 1
 END
 SET @CALC1 = @CALC1 + 1
END

Mais uma…

SET nocount on
go
declare @i int
set @i = 3
declare @f int
set @f = 20
declare @1 int set @1 = 1
declare @2 int set @2 = 2
declare @3 int set @3 = 3
declare @4 int set @4 = 4
declare @5 int set @5 = 5
declare @6 int set @6 = 6
declare @7 int set @7 = 7
declare @8 int set @8 = 8
declare @9 int set @9 = 9
declare @10 int set @10 = 10
WHILE @i <= @f
BEGIN
BEGIN
SELECT convert(varchar(2),@1)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i)
SELECT convert(varchar(2),@2)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i)
SELECT convert(varchar(2),@3)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i)
SELECT convert(varchar(2),@4)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i)
SELECT convert(varchar(2),@5)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i)
SELECT convert(varchar(2),@6)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i)
SELECT convert(varchar(2),@7)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i)
SELECT convert(varchar(2),@8)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i)
SELECT convert(varchar(2),@9)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i)
SELECT convert(varchar(2),@10)+'x'+convert(varchar(20),@i)+'='+convert(varchar(20),@i)
END
SET @i = @i + 1
END

E a última…

declare @i int
declare @y int
declare @num varchar(max)
declare @num2 varchar(max)
declare @res varchar(max)

-- Atribui @y = Tabuada começa do 1 -
set @y=1
-- Enquanto @y menor ou igual a 10, vai ate tabuada do 10 -
while @y<=10
-- Inicio 1
begin
 -- Atribui @i = 1 começa com x 1, no caso 1 x 1 ou então(@y x @i )
 set @i=1
 -- Enquanto @i menor ou igual a 10 - vai ate x 10
 while @i<=10
 -- Inicio 2
 begin
 -- Atribui @num = @i
 set @num = @i;
 -- Atribui @num2 = @y
 set @num2 = @y;
 -- Atribui @res = @y * @i
 set @res = @y*@i
 -- Mostrando o Resultado da tabuada concatenando os resultados -
 print @num2+'x'+@num+'='+@res
 -- Atribui @s a ele mesmo + 1, 'próximo valor de @s' - soma para ir ao próximo numero -
 set @i=@i+1
 -- Inicio 2
 end
 -- Atribui @y a ele mesmo + 1, 'próximo valor de @y' - soma para ir a proxima tabuada -
 set @y=@y+1
 -- Imprime enter e '---------' enter - só o espaçamento entre tabuadas
 print Char(13)+'----'+Char(13)
-- Fim Inicio 1
end

Maldito seja Case Sensitive

Apenas para deixar claro: Não sou contra a utilização de CS e AS.

O desenvolvedor tem que lembrar que quando a base está com o collation em CS e ninguém alterou a coluna da pesquisa para CI ele vai ter resultados diferentes quando usa essa coluna em um distinct ou no where…

A algum tempo um desenvolvedor veio conversar comigo porque ele estava tendo problemas em um resultado de um select,,, coisa pouca, em uma tabela de uns 1kk de registros ele queria usar distinct para recuperar umas informações, quando ele usava o order by ele mostrava muitos resultados parecidos…

Lembrei ele que a base era CS e que ou teria que usar UPPER/LOWER ou passar um collation para a coluna da pesquisa ele ficou me olhando como se eu fosse louco…. ta certo,,, ele não estava errado,,, mas era uma solução rápida e indolor…

Exemplo:

CREATE DATABASE [BDTESTE]
COLLATE Latin1_General_100_CS_AS
GO

USE BDTESTE
GO

create table tbl_teste(
nome varchar(20)
)
insert into tbl_teste
select 'teste'
union
select 'Teste'
union
select 'tEstE
union
select 'TESTE'

SELECT *
from tbl_teste

select distinct(nome)
from tbl_teste

select distinct(UPPER(nome))
from tbl_teste

select distinct(nome) COLLATE sql_latin1_general_cp1_ci_ai
from tbl_teste

Existem outras formas de solucionar isso,,, trocar o collation da coluna direto na tabela, criar uma view, etc etc…