Temat: [TSQL] Dynamiczy SQL

Witam,

zastanawiam się nad optymalnym rozwiązaniem...
Mam dwie tabele. Nazwę je Formularz, Bledy.
W tabeli Formularz mam zgromadzone odpowiedzi jakie udzielili użytkownicy na pytania, zaś w tabeli Bledy zdefiniowane są warunki poprawności dla formularza zapisane w sql-u.

W wyniku mam otrzymać informację o poprawności danego formularza
i zaktualizować jego stan.

Możliwe rozwiązania:
1) zastosowanie kursora i tabel tymczasowych dla każdego warunku osobno
(zastosowanie kursora nie jest optymalne)
2) skleić wszystkie warunki, rozdzielając 'or' i wstawić w 'where' (nie jestem pewne czy otrzymam taki sam wyniki jakbym wykonywała zapytania dla każdego warunku osobno)

Podobny przypadek http://stackoverflow.com/questions/13975131/checking-w...
Tomasz Anciński

Tomasz Anciński Programista Systemów
Sterowania,
Blumenbecker
Engineering...

Temat: [TSQL] Dynamiczy SQL

jak byś podała minimalnie więcej szczegółów to nic by się nie stało, poza tym raczej odradzam dynamiczy sql z powodów bezpieczeństwa. to jest jakiś test do sprawdzenia w bazie czy chcesz sprawdzać poprawność wprowadzanych danych ??
Nikodem Dobrzański

Nikodem Dobrzański Architekt systemu,
BizTech Konsulting
S.A.

Temat: [TSQL] Dynamiczy SQL

Gosiu,
Jak Tomasz napisał wyżej, powinnaś pokazać definicje utworzenia tabel (create table Formularz ... create table Bledy) oraz wypełnienie ich przykładowymi danymi (insert into Formularz(...) values(...)). To po to, żeby reszta mogła skopiowaniem tych poleceń odtworzyć sobie Twoją sytuację. Zresztą, to standard przy pytaniu o zapytania.
Zastosowanie kursora nie jest optymalne, bo czasami nawet tysiące razy wolniejszy od zwykłego select. Dynamicznym tsql można wymodelować wiele danych i jest bardzo przydatnym rozwiązaniem, tylko trzeba być bardzo ostrożnym przy jego używaniu. Zobacz sobie przykłady na temat sql injection. To jest główne zagrożenie. W przypadku zwykłego zapytania nie masz kontroli nad tym, co napisze do tablicy Bledy użytkownik. Optymalizacja takiego zapytania, wywoływanego wielokrotnie, też pozostawia sporo do życzenia.

Kwestia poprawności wprowadzania danych do formularza: w TSQL masz naprawdę sporo możliwości, począwszy od zawężenia CHECK, które ustawiasz na kolumnie, do FOREIGN KEY. I właśnie te rzeczy mają Tobie chronić tablicę przez nieprzewidzianym przez twórcę wstawianiem nieprawidłowych danych (użytkownicy mają na ten temat inne zdanie).

Temat: [TSQL] Dynamiczy SQL

Nie mam wpływu na jakość danych, toteż kluczowe znaczenie ma tu kontrola.

Proszę poniżej przykładowe dane:




DROP TABLE [dbo].[formularz]
CREATE TABLE [dbo].[formularz](
[nr] [varchar](10) NOT NULL,
[p1] [int] NULL,
[p2] [int] NULL,
[p3] [int] NULL,
[stan] [int] NULL
)
DROP TABLE [dbo].[bledy]
CREATE TABLE [dbo].[bledy](
[id] [int] not NULL,
[sqlTxt] [varchar](20) NULL,
[poziomBledu] [int] NULL
)

insert into [dbo].formularz(nr, p1, p2, p3, stan) values('123', 1, 0, 1, 0)
insert into [dbo].formularz(nr, p1, p2, p3, stan) values('124', 1, 1, 1, 0)
insert into [dbo].formularz(nr, p1, p2, p3, stan) values('125', 0, 0, 1, 0)
insert into [dbo].formularz(nr, p1, p2, p3, stan) values('126', 1, 1, 1, 0)

insert into [dbo].bledy(id, sqlTxt, poziomBledu) values(1, 'f.p1=1 and f.p2=1', 1)
insert into [dbo].bledy(id, sqlTxt, poziomBledu) values(2, 'f.p1=0 and f.p3=1', 1)
insert into [dbo].bledy(id, sqlTxt, poziomBledu) values(3, 'f.p2=1 and f.p3=0', 2)

select * from [dbo].[formularz]
select * from [dbo].[bledy]



W tabeli formularz są odpowiedzi na pytania (p1, p2, p2) w postaci 0, 1 (tak, nie). Przechowywana jest też informacja o poprawności formularza (stan == 0 oznacza przed kontrolą).

Warunki jakie określają poprawność formularza są zdefiniowane w tabeli błędy. Znaczenie też ma poziom błędu (1, 2). W zależności poziomu ustawiany jest odpowiedni stan formularza.Ten post został edytowany przez Autora dnia 03.09.13 o godzinie 17:54
Nikodem Dobrzański

Nikodem Dobrzański Architekt systemu,
BizTech Konsulting
S.A.

Temat: [TSQL] Dynamiczy SQL

Osoba, która ma uprawnienia do utworzenia tych tablic, może znacząco zmniejszyć rozmiar tej tablicy.
A na pewno powtórka ze składni

Skoro kolumny p1, p2, p3 przyjmują wartość z zakresu 0-1, to po co tam stoi INT? Powinien być BIT. Jeżeli chcesz, żeby osoba wypełniała te pola, to dajesz NOT NULL.
Typów wbudowanych nie otaczamy nawiasami kwadratowymi, czyli zamiast [varchar](10) powinno stać VARCHAR(10).
Nazwa kolumny nr sugeruje, że stoi tam identyfikator konkretnego formularza, który jest unikalny w całej tablicy. TINYINT to za mało, albo SMALLINT, albo INT z IDENTITY(1,1) NOT NULL. UNIQUEIDENTIFIER też daje taką funkcjonalność, ale nie jest on stosowany do szybkich wpisów, wygenerowanie GUID trochę trwa, jego przeznaczenie to głównie tablice słownikowe do replikacji.
Rozprawmy się z kolumną stan. Tu, do wyboru, mamy CHAR albo TINYINT. Ten pierwszy zajmuje mniej miejsca, ale w przypadku zastosowania operatorów non-equal w zapytaniu (znaki <, > itd) się nie nadaje. Na placu boju pozostaje TINYINT. Ponieważ chcemy, żeby miał już wartość domyślną, dodajemy NOT NULL DEFAULT 0.
Nie widzę powiązania tablicy formularz z tablicą bledy, ale to w sumie niepotrzebne. Jeżeli wartość zależy od wyliczenia kilku kolumn, to dlaczego nie zastosować utworzyć widoku, który bazuje na tablicy? Jeżeli nie ma innych "ale", to powinno wyglądać to mniej więcej tak:

CREATE TABLE [dbo].[formularz](
nr INT IDENTITY(1,1) NOT NULL
, p1 BIT NOT NULL
, p2 BIT NOT NULL
, p3 BIT NOT NULL
, stan TINYINT NOT NULL DEFAULT 0);

CREATE VIEW [dbo].[vFormularz]
AS
SELECT
nr
, p1
, p2
, p3
, stan
, CASE
WHEN p1=1 AND p2=1 THEN 1
WHEN p1=0 AND p3=1 THEN 1
WHEN p2=1 AND p3=0 THEN 2
ELSE 0
END AS bledy
FROM
[dbo].[formularz];

Jakby były jakieś inne ograniczenia, pisz.

Temat: [TSQL] Dynamiczy SQL

Nikodemie dziękuję Ci za obszerną odpowiedź. Masz rację co do tworzenia tabel.
Kod, który napisałam jest pseudo kodem. Nie wnikam w strukturę tabeli i wartości jakie są w odpowiedziach (w rzeczywistych danych są to też wartości słownikowe, mogą też być stringi).

W moim przykładzie należy zwrócić głownie uwagę na to jak budować dynamicznie optymalne zapytanie. W przykładowej tabeli Bledy zdefiniowałam tylko trzy wiersze, a w rzeczywistości tych warunków będzie kilkadziesiąt (tabela Bledy definiuje poprawności jednego formularza).

Być może zbudowanie widoku będzie dobrym rozwiązanie. Ja tworzę tabelę Bledy z uwagi na przejrzystość.Ten post został edytowany przez Autora dnia 03.09.13 o godzinie 22:47
Tomasz Anciński

Tomasz Anciński Programista Systemów
Sterowania,
Blumenbecker
Engineering...

Temat: [TSQL] Dynamiczy SQL

to co potrzebujesz to są najprostsze z możliwych zapytań...

tutaj masz kod tworzący nową bazę egzamin i tabele z przykładowymi danymi, piszesz że to psełdo kod bo faktycznie brakuje tam paru rzeczy między innymi wiązania pomiędzy wzorem odpowiedzi a pytaniami (przyjąłem że to wiązanie będzie po id ale w rozwiązaniu pordukcyjnym proponował bym jednak powiązać to przez osobne pole...)

test jest przeprowadzony na 300 arkuszach testów wypełnionych losowymi odpowiedziami (nie brałem pod uwagę filtrowania sprawdzonych arkuszy i braku odpowiedzi która powinna być też błędem)

kod na przykładowe dane :
set nocount on;
Use master;
if DB_ID('Egzamin') IS NULL
CREATE DATABASE Egzamin;
GO

USE Egzamin;
GO

SET NOCOUNT ON;
IF OBJECT_ID('NUM', 'U') IS NOT NULL
DROP TABLE DBO.NUM;
CREATE TABLE NUM(N INT NOT NULL PRIMARY KEY);

IF OBJECT_ID('Formularz','U') IS NOT NULL
DROP TABLE DBO.Formularz;
CREATE TABLE [dbo].[Formularz](
[id.formularz] [int] IDENTITY(1,1) NOT NULL,
[nr.formularza] [nchar](10) NULL,
[p.1] [bit] NULL,
[p.2] [bit] NULL,
[p.3] [bit] NULL,
[stan] [bit] NULL
) ON [PRIMARY]

IF OBJECT_ID('Bledy','U') IS NOT NULL
DROP TABLE DBO.Bledy;
CREATE TABLE [dbo].[Bledy](
[id.bledy] [int] IDENTITY(1,1) NOT NULL,
[bp.1] [bit] NULL,
[bp.2] [bit] NULL,
[bp.3] [bit] NULL,
[poziomBledu] [int] NULL
) ON [PRIMARY]

DECLARE @MAX AS INT , @RC AS INT;
SET @MAX = 1000;
SET @RC =1;

INSERT INTO DBO.NUM(N) VALUES (1);
WHILE @RC *2 <=@MAX
BEGIN
INSERT INTO DBO.NUM(N) SELECT N+@RC FROM DBO.NUM;
SET @RC = @RC *2;
END;
INSERT INTO DBO.NUM(N)
SELECT N+@RC FROM NUM WHERE N+@RC <= @MAX;
GO
DECLARE @ILOSC_TESTOW AS INT, @ZIARNO as INT
SET @ILOSC_TESTOW = 300
SET @ZIARNO = 10

INSERT INTO DBO.Formularz([nr.formularza] ,[p.1] ,[p.2] ,[p.3] ,[stan])
SELECT ('TEST NR' + CONVERT(nvarchar(10), N)) AS [nr.formularza],
CASE WHEN ((abs(CHECKSUM(newid())+2147483649)/4294967296) * @ZIARNO) >=4 THEN 0 ELSE 1 END AS [P.1],
CASE WHEN ((abs(CHECKSUM(newid())+2147483649)/4294967296) * @ZIARNO) >=4 THEN 0 ELSE 1 END AS [P.2],
CASE WHEN ((abs(CHECKSUM(newid())+2147483649)/4294967296) * @ZIARNO) >=4 THEN 0 ELSE 1 END AS [P.3],
CASE WHEN ((abs(CHECKSUM(newid())+2147483649)/4294967296) * @ZIARNO) >=4 THEN 0 ELSE 1 END AS [STAN]
FROM DBO.NUM
WHERE N <= @ILOSC_TESTOW

INSERT INTO [dbo].[Bledy]([bp.1] ,[bp.2] ,[bp.3] ,[poziomBledu])
SELECT CASE WHEN ((abs(CHECKSUM(newid())+2147483649)/4294967296) * @ZIARNO) >=4 THEN 0 ELSE 1 END AS [PB.1],
CASE WHEN ((abs(CHECKSUM(newid())+2147483649)/4294967296) * @ZIARNO) >=4 THEN 0 ELSE 1 END AS [PB.2],
CASE WHEN ((abs(CHECKSUM(newid())+2147483649)/4294967296) * @ZIARNO) >=4 THEN 0 ELSE 1 END AS [PB.3],
NULL
FROM DBO.NUM
WHERE N<= @ILOSC_TESTOW

kod funkcji sprawdzającej...
USE [Egzamin]
GO
/****** Object: UserDefinedFunction [dbo].[SF_SPRAWDZ_TETS] Script Date: 2013-09-03 23:31:13 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================

CREATE FUNCTION [dbo].[SF_SPRAWDZ_TETS]
(
-- Add the parameters for the function here
@num_testu as int
)

RETURNS INT
AS
BEGIN
DECLARE @WYNIK AS INT =0, @licznik_b as int;
-- Add the T-SQL statements to compute the return value here

SELECT @WYNIK = CASE WHEN F.[p.1] = B.[bp.1] THEN @wynik + 0 ELSE @wynik + 1 END
,@WYNIK = CASE WHEN F.[p.2] = B.[bp.2] THEN @WYNIK + 0 ELSE @WYNIK + 1 END
,@WYNIK = CASE WHEN F.[p.3] = B.[bp.3] THEN @WYNIK + 0 ELSE @WYNIK + 1 END

FROM DBO.Formularz F LEFT JOIN DBO.Bledy B ON F.[id.formularz] = B.[id.bledy]
WHERE F.[id.formularz] = @num_testu
-- Return the result of the function
RETURN @WYNIK

END

GO
no i kod zwykłego selecta w którym otrzymujesz ilość błędów w danym pytaniu..

/****** Script for SelectTopNRows command from SSMS ******/
SELECT TOP 1000 F.[id.formularz]
,f.[nr.formularza]
,[dbo].[SF_SPRAWDZ_TETS] (f.[id.formularz]) as bledy
,f.[p.1],b.[bp.1]
,f.[p.2],b.[bp.2]
,f.[p.3],b.[bp.3]
,f.[stan]
FROM [Egzamin].[dbo].[Formularz] F
join Egzamin.dbo.Bledy B on f.[id.formularz]=b.[id.bledy]
where f.stan = 0

GO

jak będziesz miała pytania to pisz...
i tak jak napisałem lepiej chyba będzie ci rozbić to na osobne pytania, bo będą powiązane z konkretnym wzorem odpowiedzi ustalonym raz i jak będziesz chciała np. pomieszać pytania do testu losowo to nie będziesz tworzyć dużej tabeli wzoru odpowiedzi... chyba wiesz o co mi chodzi... nie ma też problemu żeby zamiast selecta którego wstawiłem zrobić procedurę która sprawdzi arkusze, zrobi update w kolumnie stan i zmieni poziomBledu...
nie potrzeba widoków tabel tymczasowych i tym podobnych...
a i jeszcze jedno... nie przejmuj się tabelą num bo powstała ona tylko w celu utworzenia przykładowych danych

tak rzuciłem okiem tylko jeszcze na próbie porównania 30 tyś pytań u mnie na kompie trwało to 1:16 s...Ten post został edytowany przez Autora dnia 03.09.13 o godzinie 23:57

Temat: [TSQL] Dynamiczy SQL

Uruchomiłam skrypt, wszytko działa ... tylko chyba nie za jasno wytłumaczyłam.
W tym skrypcie tworzony jest wzorzec/szablon właściwych odpowiedzi, a następnie porównywany jest z odpowiedziami użytkownika. Takiego wzorca nie mogę zbudować, bo w zależności od odpowiedzi na dane pytanie użytkownik może 'pójść' inną ścieżką np jeśli w pytaniu nr 2. odpowie tak(1) przejdzie do pytania nr 3., jeśli odpowie nie(0) przejdzie do pytania nr 5 (pytania nr 3. i 4. mają pozostać nieuzupełnione).

Wiązania nie ma między tabelą Formularze i Bledy. Relacja między tymi tabelami jest jeden do wielu - na jednym formularzu może występować wiele błędów. Wszystkie możliwe błędy jakie mogą występować na jednym formularzu opisuje cała tabela Bledy (a nie jeden wiersz).
Wracając do wcześniej przesłanych przeze mnie danych mogę określić, które formularze są błędne statycznym zapytaniem:


select * from [dbo].formularz f
where (f.p1=1 and f.p2=1)
or (f.p1=0 and f.p3=1)
or (f.p2=1 and f.p3=0)

Wynik:
id nr p1 p2 p3
---------------------------------
2 124 1 1 1
3 125 0 0 1
4 126 1 1 1



Tylko jeden formularz (wiersz z danymi: '123'(nr), 1(p1), 0(p2), 1(p3), 0(stan)) jest poprawny.Ten post został edytowany przez Autora dnia 04.09.13 o godzinie 22:09
Tomasz Anciński

Tomasz Anciński Programista Systemów
Sterowania,
Blumenbecker
Engineering...

Temat: [TSQL] Dynamiczy SQL

No zgadza się... dlatego proponuję rozbicie na pytania,
- po pierwsze każde pytanie ma odpowiedzi - nie ważne ile (2 poprawne albo tylko jedna poprawna obojętnie)
- czyli istnieje dla pojedynczego pytania tylko jeden schemat odpowiedzi...

Załóżmy że tworzysz 500 pytań, oczywiście nadal mówimy o testach sprawdzających wiedzę lub coś innego. Jeżeli to będzie jakiś wywiad jak u lekarza to powinnaś sobie wstępnie jakieś grafy narysować i pomysł sam się pokaże. Tak czy inaczej jeśli będziesz mieć pojedyncze pytania i powiązane z nimi wzory odpowiedzi to które wybierzesz do testu (arkusza z pytaniami) zależeć będzie od innego mechanizmu.

Piszesz że pytania w zależności od udzielonej odpowiedzi będą wywoływały jakieś pytania, tzn jeśli w pytaniu nr 1 zaznaczę odpowiedź 3 to jako następne pytanie ukaże mi się pytanie nr 7 ale gdybym wybrał odpowiedź 2 to pytanie 12 czy dobrze rozumiem ??
Jeśli tak to w puli 500 pytań tworzysz, nie wiem 5 grup po 100 pytań (może być więcej może być mniej zależy od projektu, testu) i tak po wybraniu odpowiedzi 3 dostaję pytanie z puli 4 czyli od 401 do 500. Wszystko zależy od projektu ale mechanizm tworzenia testu (arkusza) powinien być osobnym mechanizmem bo wtedy obojętnie jakie pytania pojawiają ci się na teście (wymieszane, losowe, szablonowe) zawsze są traktowane przez mechanizm sprawdzający jako jedno pytanie i porównywane do wzorca z odpowiedziami utworzonego tylko dla danego pytania.

Dobrze by było jak byś napisała co w zamyśle ma robić aplikacja bo może idziemy zupełnie inną ścieżką, albo chociaż porównała do istniejącej podobnej aplikacji...
Rafał Stogniew

Rafał Stogniew Analityk, konsultant
ds. wdrożeń.

Temat: [TSQL] Dynamiczy SQL

Czesc odnosze wrazenie, iz chodzi tu raczej o inne podejscie do samej struktury danych moze zamiast budowac dynamiczego sqla wystarczy stworzyc tabele ze sciezkami zawierajacymi kolumny: pytanie_biezace_id oraz pytanie_kolejne_id co umozliwi napisanie prostych zapytan z logika jak rowniez umozliwi stworzenie prostego interfejsu do definicji roznych sciezek dla uzytkownika bez znajomosci sqla.

Temat: [TSQL] Dynamiczy SQL

Mając zbiór danych taki jak zamieściłam wcześniej w wyniku chcę otrzymać:

nr stan
-------------------------
123 Poprawny
124 Błąd akceptowalny
125 Błąd akceptowalny
126 Błąd akceptowalny
127 Do poprawy

[Do tabeli formularz dodałam jeszcze jeden wiersz, żeby były widoczne wszystkie zdefiniowane poziomy błędów
insert into [dbo].formularz(nr, p1, p2, p3, stan) values('127', 1, 1, 0, 0) ]

By uzyskać taki wynik poniżej stosuję kursor. Stan jest wyliczany jako maksymalny poziom błędu.


CREATE PROCEDURE skontroluj
AS
BEGIN
DECLARE
@sql VARCHAR(max)
,@sqlText_v varchar(max)
,@poziomBledu_v int
IF OBJECT_ID('tempdb..#BledneRekordy') IS NOT NULL
DROP TABLE #BledneRekordy
CREATE TABLE #BledneRekordy
(
nr varchar(10)
,poziomBledu int
)

DECLARE db_cursor CURSOR FOR
SELECT sqlTxt
,poziomBledu
FROM [dbo].[bledy]


OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @sqlText_v, @poziomBledu_v

WHILE @@FETCH_STATUS = 0
BEGIN
set @sql =
'
insert #BledneRekordy
select
f.nr
,' + str(@poziomBledu_v) + ' as poziomBledu
from [dbo].formularz f where ' + @sqlText_v + '
'

exec (@sql)
FETCH NEXT FROM db_cursor INTO @sqlText_v, @poziomBledu_v
END
CLOSE db_cursor
DEALLOCATE db_cursor IF object_id('tempdb..##Zbiorcza') is null
BEGIN

SET @sql =
'
create table ##Zbiorcza
(
nr varchar(10)
,poziomBledu int
)
'
END EXEC (@sql)
SET @sql =
'delete ##Zbiorcza
insert ##Zbiorcza
select
nr
,max(poziomBledu) maxPoziomBledu
from #BledneRekordy
group by nr
' EXEC (@sql)
UPDATE [dbo].formularz
SET stan = z.poziomBledu
FROM [dbo].formularz f join ##Zbiorcza z on f.nr = z.nr
SET @sql =
'
select f.nr
,CASE f.stan
WHEN 0 THEN ''Poprawny''
WHEN 1 THEN ''Błąd akceptowalny''
WHEN 2 THEN ''Do poprawy''
END stan
from [dbo].formularz f
'
EXEC(@sql)
END

Tomasz Anciński

Tomasz Anciński Programista Systemów
Sterowania,
Blumenbecker
Engineering...

Temat: [TSQL] Dynamiczy SQL

no nie wiem... ja bym tego tak nie zrobił...

Temat: [TSQL] Dynamiczy SQL

Przy kursorach spada wydajność ... toteż pytam i rozważam :)

konto usunięte

Temat: [TSQL] Dynamiczy SQL

Ja natomiast, mam takie pytanie trochę nie związane tematem ale nie chcę zaśmiecać forum jakimiś takimi prościznami (jak sądzę).

mam takie oto proste zapytanie:


SELECT OBJECT_ID(N'AdventureWorks2012.Production.WorkOrder')
AS 'Object ID';


wzięte stąd:
http://technet.microsoft.com/pl-pl/library/ms190328.aspx

Mam ostatnio mocno do czynienia z SQL Serverem (wcześniej z oracle gdzie nie pamiętam takiego czegoś) więc mam pytanie co oznacza to N przed nazwą tabeli i schematami. Bo widziałem, że też zostało użyte wyżej OBJECT_ID('nazwa_tabeli', 'U') gdzie U oznacza że tabela jest zdefiniowana przez użytkownika (nie systemowa). Niestety nie znalazłem nic odnośnie tego N przed nazwą. Pod linkiem wyżej też widać właśnie, że przed parametrem U jest także N. Z góry dzięki za wyjaśnienie :)Ten post został edytowany przez Autora dnia 10.09.13 o godzinie 20:06

Temat: [TSQL] Dynamiczy SQL

N - National. Jak w nvarchar. Literał będzie traktowany jako unicode; jeśli przekazywany do funkcji/procedury - to jako nchar/nvarchar zamiast char/varchar.
http://www.google.pl/search?q=T-SQL+N+prefixTen post został edytowany przez Autora dnia 10.09.13 o godzinie 20:22

konto usunięte

Temat: [TSQL] Dynamiczy SQL

bardzo dziękuję :) z nvarchar'em nie skojarzyłem, teraz to się wydaje takie oczywiste ;)
Grzegorz G.

Grzegorz G. ASE / Systems
Architect, Syniverse

Temat: [TSQL] Dynamiczy SQL

Małgorzata B.:
Przy kursorach spada wydajność ... toteż pytam i rozważam :)

To ja bym to inaczej zrobił - wygenerował zapytanie i je odpalił (czy to z palca, czy jako dynamiczny sql). Nie mam SQL Servera pod ręką, ale MSSQL Oracle dwa bratanki ;-). Na pewno jakoś to dasz radę przetłumaczyć. Jedyne nieintuicyjne to ta kolumna "lno" - chodzi o to, żeby błędy o wyższym poziomie miały wyższy priorytet niż te o niższym.

SQL> DROP TABLE formularz;

Table dropped.

SQL> DROP TABLE bledy;

Table dropped.

SQL>
SQL> CREATE TABLE formularz(
2 nr varchar(10) NOT NULL,
3 p1 number NULL,
4 p2 number NULL,
5 p3 number NULL,
6 stan number NULL
7 );

Table created.

SQL>
SQL> CREATE TABLE bledy(
2 id number not NULL,
3 sqlTxt varchar(20) NULL,
4 poziomBledu number NULL
5 );

Table created.

SQL>
SQL> insert into formularz(nr, p1, p2, p3, stan) values('123', 1, 0, 1, 0);

1 row created.

SQL> insert into formularz(nr, p1, p2, p3, stan) values('124', 1, 1, 1, 0);

1 row created.

SQL> insert into formularz(nr, p1, p2, p3, stan) values('125', 0, 0, 1, 0);

1 row created.

SQL> insert into formularz(nr, p1, p2, p3, stan) values('126', 1, 1, 1, 0);

1 row created.

SQL> insert into formularz(nr, p1, p2, p3, stan) values('127', 1, 1, 0, 0);

1 row created.

SQL>
SQL> insert into bledy(id, sqlTxt, poziomBledu) values(1, 'f.p1=1 and f.p2=1', 1);

1 row created.

SQL> insert into bledy(id, sqlTxt, poziomBledu) values(2, 'f.p1=0 and f.p3=1', 1);

1 row created.

SQL> insert into bledy(id, sqlTxt, poziomBledu) values(3, 'f.p2=1 and f.p3=0', 2);

1 row created.

SQL>
SQL> select * from formularz;

NR P1 P2 P3 STAN
---------- ---------- ---------- ---------- ----------
123 1 0 1 0
124 1 1 1 0
125 0 0 1 0
126 1 1 1 0
127 1 1 0 0

SQL> select * from bledy;

ID SQLTXT POZIOMBLEDU
---------- -------------------- -----------
1 f.p1=1 and f.p2=1 1
2 f.p1=0 and f.p3=1 1
3 f.p2=1 and f.p3=0 2

SQL>
SQL> select null lno, 'select nr, p1, p2, p3, stan, case '
2 from dual
3 union all
4 select poziomBledu lno, ' when ' || sqlTxt || ' then ' ||
5 case poziomBledu
6 when 0 then '''Poprawny'''
7 when 1 then '''Akceptowalny'''
8 when 2 then '''Do poprawy'''
9 end
10 from bledy
11 union all
12 select -1 lno, ' else ''Poprawny''
13 end
14 from formularz f'
15 from dual
16 order by lno desc nulls first;

LNO 'SELECTNR,P1,P2,P3,STAN,CASE'
---------- ---------------------------------------------------
select nr, p1, p2, p3, stan, case
2 when f.p2=1 and f.p3=0 then 'Do poprawy'
1 when f.p1=1 and f.p2=1 then 'Akceptowalny'
1 when f.p1=0 and f.p3=1 then 'Akceptowalny'
-1 else 'Poprawny'
end
from formularz f


SQL> select nr, p1, p2, p3, stan, case
2 when f.p2=1 and f.p3=0 then 'Do poprawy'
3 when f.p1=1 and f.p2=1 then 'Akceptowalny'
4 when f.p1=0 and f.p3=1 then 'Akceptowalny'
5 else 'Poprawny'
6 end
7 from formularz f
8 /

NR P1 P2 P3 STAN CASEWHENF.P2
---------- ---------- ---------- ---------- ---------- ------------
123 1 0 1 0 Poprawny
124 1 1 1 0 Akceptowalny
125 0 0 1 0 Akceptowalny
126 1 1 1 0 Akceptowalny
127 1 1 0 0 Do poprawy

Temat: [TSQL] Dynamiczy SQL

Panowie dziękuję Wam za zainteresowanie i wypowiedzi, które pozwoliły mi spojrzeć na moje zagadnienie bardziej realnie. Zapewne skorzystam z Waszych 'rad' ...
Przemysław B.

Przemysław B. Jestem programistą
C++ oraz architektem
kodu, potrafię pr...

Temat: [TSQL] Dynamiczy SQL

Dajcie spokój Panowie z takimi radami. Projekt bazy jest zrypany i ciężko coś z tego wyczarować. Powinny być tabele formularze pytania odpowiedzi. Formularze w relacji jeden do wielu z pytaniami a odpowiedzi jako tabela asoscjacyjna pomiędzy pytaniami a użytkownikami. Przy takiej strukturze zapytanka to proste selecty i nic nie trzeba czarować z dynamicznym sql'em ani kursorami.
Grzegorz G.

Grzegorz G. ASE / Systems
Architect, Syniverse

Temat: [TSQL] Dynamiczy SQL

Przemysław B.:
Dajcie spokój Panowie z takimi radami. Projekt bazy jest zrypany i ciężko coś z tego wyczarować. Powinny być tabele formularze pytania odpowiedzi. Formularze w relacji jeden do wielu z pytaniami a odpowiedzi jako tabela asoscjacyjna pomiędzy pytaniami a użytkownikami. Przy takiej strukturze zapytanka to proste selecty i nic nie trzeba czarować z dynamicznym sql'em ani kursorami.

Niestety nie zawsze żyje się w idealnym świecie, czasami trzeba czarować. I to abstrahując od kwestii, że struktura powyżej nie rozwiązuje problemu, no ale to detal, da się go rozwiązać samą strukturą, ale nie taką :P.

Następna dyskusja:

[SQL] Zapytanie TSQL z wyko...




Wyślij zaproszenie do