» »

SQL vprašanje

SQL vprašanje

jerneju ::

Rad bi ustvaril tabelo, ki ima za stolpce dni v mesecu.

1, 2, 3, 4, 5,...

to pomeni, da bi moral napisati

SELECT
blabla as 1, blabla as 2, blabla as 3,...

pa bi rad kaj splošnega

recimo za n od 1 do 28/29/30/31
{
blabla as 'n'
}

kdo ve kak hint?

Brilko ::

Najprej razumljivo spiši vprašanje...

rad bi ustbvaril... torej morem uporabiti SELECT...
rad bi nekaj pojedel... torej morem iti na hrib in skočiti s padalom... :D

Pa si prepričan da se ti splača delat stolpce za vsak dan v mesecu? Mislim da to ni pametno. Zakaj sloh rabiš? Če res želiš, se da karkoli tudi z zanko anpisati kot si ti hotel, čeprav nevem kaj si hotel...

Dost je blo, boš se še mogu mal rpetegnat, da bom še kaj napisu!

jerneju ::

Rad bi ustvaril tabelo.

Nekaj sem že naredil in sicer tole:

SELECT
ime_priimek, (blabla) AS '1', (blabla) AS '2', ... (blabla) AS '28',... (blabla) AS '31'
FROM
IMENIK

tabela bi bila torej takšna, da bi bil v prvem stolpcu ime+priimek, v drugem podatek (recimo številka) za 1. dan v mesecu itd. do zadnjega dne. Zadnji stolpec bi bil pa vsota vseh dni v mesecu.

Za blabla imam jaz ze narejen SELECT stavek, ki vrne stevilko int, potrebuje pa paramtrte ime_priimek (tega dobimo iz IMENIK) in dva datuma. To ze imam.

Problem je le v tem, ker se mi zdi zamotoma to ponavljati 31-krat. Za zadnje stiri dneve bi itak moral pisati se if oz. CASE stavke.

Zanima me, ce se da napisti za te dneve samo en splošni stavek pač in pač našopa teh 28-31 stolpcev ali kako drugače.

V splošnem programiranju bi sicer sam znav naresti sioil zanko, da pač ponavlja od 1 do 28-31, samo to je pa sql pa ne znam.

Mogoče je kaka druga varianta pa for sploh ne potrebujemo?

1 2 3 4 5 6 7 8 9 ,,,,
JANEZ NOVAK 8 8 8 8 8 8 8 8 8
MICA VIDMAR 8 6 7 8 7 6 7 8 7
TONČKA DOLENC 7 8 6 7 8 8 7 6 7...

Matej_ ::

Tudi tvoj zadnji post ni ravno vzor razumljivosti. Če ti SQL in načrtovanje baz nista domača pojma, potem pač lepo razloži kaj želiš s svojim poskusom narediti - kakšen je problem iz prakse ki ga poizkušaš rešiti. Iz tvojih "blodenj" kake smiselne zaključke bolj težko potegnem.
To z 31-timi stolpci je po moje zelo slaba ideja kakorkoli pogledaš, sploh tisti zadnji stolpec z vsoto, tega se v bazo pač ne vnaša ampak po potrebi izračuna iz že vnešenih podatkov. Razmišljaš preveč v smeri dela s preglednicami (Excell).

Na ravni baze to lepo razdeliš na več tabel. Recimo v eni imaš osebe s ključi, ki jih potem uporabiš v tabeli s tedni. Npr.:

Tabela osebe:
IDoseba;NazivOseba
1;Micka Novak
2;Francelj Cokalj
3;Jože Celjan

Tabela tedni
IDoseba;IDteden;UreDela
1;1;8
1;2;8
1;3;9
1;4;8

jerneju ::

Jaz imam dve tabeli v eni bazi.

V prvi tabeli je seznam delavcev, v drugi tabeli, ki je pac z neko sifro vezana na prvo, je pa kao en koledar.

V tem koledarju je razvidno, od kdaj do kdaj na kateri dan je kaka oseba pac delala. Jaz moram pac za vsak dan izracunati, koliko casa je neka dolocena oseba delala.

In vse te podatke za en mesec prikazati v DataGridu. Za to moram narediti eno stored proceduro.

Kako se podatki kazejo, sem pa ze zgoraj pojasnil, samo ne vem, ce sem to storil dovolj jasno.

Pac na osebe so lepo vodoravno, zgoraj so pa datumi. Od 1. pa do zadjega dne v mesecu. In kjer se pac ta stolpec datuma in vrstica osebe sekata, je pac v tistem kvadratku, torej polju tega datagrida napisano stevilo ur, minut, pac koliko casa je ta dan oseba delala.

SELECT zadevo, ki izracuna stevilo ur minut za dolocen DAN, za doloceno OSEBO, sem ze izracunal. Zdaj moram pa narediti glavni SELECT stavek, ki bi pripravil ta datagrid.

Reso ::

Saj lahko narediš "SELECT * FROM imeTabele" in potem znotraj programskega jezika z for zanko prebereš vsakega od stolpcev posebej. Ne vem kaj ti tukaj predstavlja problem:).

Bob Rock ::

Mas recimo tablei: tblDelavec in tblKoledar.
prva tabela:
------------------------------------
tblDelavec
-----------------------------------
DelavecID (AutoNumber) - kljuc
Ime
Priimek
Naslov
-----------------------------------
druga tabela:
----------------------------------
tblKoledar
----------------------------------
KoledarID(AutoNumber) - kljuc
DelavecID
Datum
UreOd
UreDo
----------------------------------

SELECT
tblKoledar.UreOd AS KoledarUreOd,
tblKoledar.UreDo AS KoledarUreDo,
tblKoledar.Datum AS KoledarDatum,
tblDelavec.Ime AS DelavecIme,
tblDelavec.Priimek AS DelavecPriimek
FROM tblDelavec
INNER JOIN tblKoledar
ON tblDelavec.DelavecID = tblKoledar.DelavecID
WHERE KoledarDatum = (Vrednost za datum)
AND tblDelavec.DelavecID = (Vrednost za ident delavca)

Zdej ce sn te prav razumel, pol mas zdej vse podatke, kar rabis za izpis, pol pa sam se izpisujes pa racunas kar se rabis.
___________________________________________________
gance hale ale cuzamen

AndrejS ::

Narediš pač dve tabeli. V prvo daš podatke o delavcu, v drugo pa stolpce

Dan, Mesec, Leto, id_delavca, pa imaš rešeno. Potem pa še pravi select napišeš pa je to to!

mercutio ::

jerneju:
Približno sem razumel kaj hočeš naredit ampak se moram strinjat z Matejem - nekih sum se v bazo ponavadi ne vpisuje, ampak se jih po potrebi izračuna "on the fly". Potem je tu tabela z 31-imi stolpci, ki ni ravno zgled lepega načrtovanja baz. Pojavlja se mi vprašanje, kako veš za kateri mesec se gre, ko bereš številke za recimo 4-ti dan v stolpcu 4? A imaš še dodaten stolpec, kjer so napisani meseci?

V glavnem, jaz bi ti priporočil, da stvar predelaš, če le upaš. Nekaj v smislu:
ID_OSEBA DATUM_ZAC DATUM_KON

Tam zabeležiš ID_OSEBE, kdaj je prišla v DATUM_ZAC, kdaj je odšla pa v DATUM_KON. In imaš vse kar rabiš. SQL bi pa bil nekako takole:
SELECT DATEDIFF(hh, DATUM_ZAC, DATUM_KON) as ST_UR
FROM tabela
WHERE DATUM_ZAC >= '2005-08-01'
AND DATUM_KON < '2005-09-01'
AND ID_OSEBA = zeljen_id_osebe

Recimo, to velja za MS SQL (drugi SQL majo lahko drugačno sintakso), vrne ti pa za vsak dan v avgustu število ur, ko je nekdo delal (je pa res, da v Access-u takega SQL stavka najbrž ne moreš nardit).

For zankam v programu se skušaj izogibat, če se le da (ker so počasne) ali pa jih delaj po že izbranih vrsticah na majhni množici zapisov. Probaj čimveč naredit z SQL stavki.

EDIT: sem popravu SQL stavek, ker sem ga malo pihnil :)

Zgodovina sprememb…

  • spremenilo: mercutio ()

mercutio ::

AndrejS:
Dan, mesec in leto se praviloma ne pišejo vsak v svoj stolpec ampak kar kot datum. Saj lahko iz datuma razbereš vse kar rabiš.

jerneju ::

Jaz sem si tako zamislil:

SELECT delavec,
(SELECT SUM(Razlika)
FROM (SELECT sifra AS IME_PRIIMEK, datumod, datumdo,
(DATEDIFF(ss, datumod, ISNULL(datumdo, datumod))) AS Razlika
FROM urnik
WHERE sifra = zaposleni_ID AND
datumod > '3.1.2001 00:00:00' AND
datumdo < '3.2.2001 00:00:00') AS Tabela)
AS '1',
(SELECT SUM(Razlika)
FROM (SELECT sifra AS IME_PRIIMEK, datumod, datumdo,
(DATEDIFF(ss, datumod,
ISNULL(datumdo, datumod))) AS Razlika
FROM urnik
WHERE sifra = zaposleni_ID AND
datumod > '3.2.2001 00:00:00' AND
datumdo < '3.3.2001 00:00:00') AS Tabela)
AS '2',
(SELECT SUM(Razlika)
FROM (SELECT sifra AS IME_PRIIMEK, datumod, datumdo,
(DATEDIFF(ss, datumod,
ISNULL(datumdo, datumod))) AS Razlika
FROM urnik
WHERE sifra = zaposleni_ID AND
datumod > '3.3.2001 00:00:00' AND
datumdo < '3.4.2001 00:00:00') AS Tabela)
AS '3',

blablabla....

FROM bazal

mercutio ::

hmm, če te prav razumem ti ni všeč, da SQL vrne dneve in št. ur kot vrstice in bi jih rabil prikazat kot stolpce. Recimo, da ti napisan SQL to tudi naredi, je pa malce kompliciran (pa kdo bo zamenjeval datume...) - lahko pa tudi, če ti je tako všeč. Drugače bi pa moral potem res na programskem nivoju pohendlat samo, a je pomembno ali kaže dneve v vrsticah ali stolpcih?

jerneju ::

Da, dnevi so v stolpcih, ljudje pa v vrsticah.

Mislim, da je tako tudi enostavnejše.

Saj kodo je lahko napisati, problem je le v tem, ker bi moral en in isti select ponoviti 31-krat!!!!!, za zadnje štiri pa napisati še CASE stavke.

Jaz sem u bistvu hotel le, da bi to za dneve v mesecu napisal le enkrat pa bi se pač to 28-31x ponovilo. Na misel mi je prišla FOR zanka, kako pa to zgleda v SQL, pa ne vem.

mercutio ::

Za FOR zanko je odvisno od SQL-a. "Plain" SQL tega ne zna, ampak se to naredi na programskem nivoju. Potem pa v programu naredi for zanko in loopaj en in isti SQL za vseh 28-31 dni v mesecu - samo ne vem, kako bo to performančno, če imaš veliko ljudi. Za majhne številke pa tudi to ne bi smel bit problem.

jerneju ::

Ne, na programskem nivoju ne pride v poštev, mora biti SQL stored procedura.

Pravzaprav bi bilo bojle, če bi naredil pač dve proceduri

Ena bi bila pač tista, ki vrne število ur na posamezen dan za določeno osebo v mesecu.

In bi klical GetHours(@delavec, @dan) in pač ven izvrglo število ur...

Zgledalo bi pa takole:

SELECT SUM(Razlika)
FROM (SELECT sifra AS IME_PRIIMEK, datumod, datumdo,
(DATEDIFF(ss, datumod, ISNULL(datumdo, datumod))) AS Razlika
FROM urnik
WHERE sifra = @delavec AND
datumod > @dan AND
datumdo < (@dan + '24:00:00')) AS Tabela

In pol bi:

SELECT delavec,
(GetHour(@delavec, '3.1.2001 00:00:00')) AS '1',
(GetHour(@delavec, '3.3.2001 00:00:00')) AS '2',
(GetHour(@delavec, '3.4.2001 00:00:00')) AS '3',

blablabla....

FROM bazal

Problem je le v tem, ker ne vem, kam naj vtaknem GetHour...

kopernik ::

Take stvari se navadno dela v aplikaciji in ne na bazi. Toda, če to moraš narediti na bazi, potem so najbrž stored procedure (v kombinaciji s kakšnim view-em) edina opcija. SQL jezik sam po sebi nima zank.

jerneju ::

Saj sem se odločil, da bom kar brez zanke.

Samo pač potrebujem še eno proceduro, ki bi jo klical za vsak dan posebej. Imela bi pa nekaj parametrov, npr. kar dva.

mercutio ::

Kakšno bazo pa imaš? Ker na Oraclu lahko komot narediš package s funkcijo in jo potem kličeš v SQL stavku podobno kot si sam napisal.

jerneju ::

Imam bazo na MS SQL Serverju 2000.

mercutio ::

Mogoče preko User Defined Functions.

Matej_ ::

Torej, glede na povedano in vse "omejitve" bi se jaz potem tega lotil na naslednji način. Žal mi MS SQL ni pri srcu kot Oracle ali MySQL in bom pri kodi samo ugibal, če ti res ne bo šlo pa lahko malo pogledam...

1. Narediš funnkcijo/proceduro ki vrne izključno ure za določen dan, kot vhodne parametre pa sprejme datum in IDzaposlenega. To si v bistvu že spisal, le še prirediš spremenljivki.

CREATE FUNCTION UreZaDan... (vhodna parametra: delavec, datum)
SELECT SUM(Razlika) INTO spremenljivka ....
RETURN spremenljivka ...


2. Narediš stored proceduro ki vrne ure po dnevih, kot parameter pa sprejme ali interval ali mesec in leto. V proceduri narediš select izključno po tabeli z osebami (imena-priimki in IDji), potem pa za ostala polja uporabiš funkcijo. Glede na to da nočeš delati s for zankami, predlagam da na začetku uporabiš CASE stavek in potem štiri možnosti za dneve v intervalu oziroma mesecu (preden začneš izpisovati preveriš koliko dni ima podani mesec):

CREATE PROCEDURE... (vhodna parametra: mesec, leto) ...
Preveri koliko dni ima mesec v leto...
CASE ....
4X tole spodaj (glede na dneve)
SELECT IME-PRIIMEK, UreZaDan(IDoseba, 1.1.2005), UreZaDan(IDoseba, 1.2.2005),UreZaDan(IDoseba, 1.3.2005).... from osebe

Zgodovina sprememb…

  • spremenil: Matej_ ()

zdravc ::

Jaz delam na bazi Oracle zato bom samo prikazal primer kako jaz to rešujem.

To je eden od primerov, ko je potrebno podatke iz vrstic prestaviti v kolone.

S strani baze je struktura enostavna, problem pa je v tem, da je vsak dan v mesecu za vsakega delavca v svojem zapisu. Tako ima en delavec v tem primeru za vsak mesec max 31 zapisov.
Ce se to želi izpisati z reportom, ni problema, ker report zna pisati počes in navzdol. Problem pa je v generatorju mask. Za tabelarični prikaz z vodoravnim prikazom dnevov v mesecu pa je potrebno izvesti preslikavo podatkov iz navpične strukture v vodoravno.

To jaz naredim (in imam kar nekaj primerov) preko view-a, kjer uporabil ukaz decode.
Decode je ukaz, ki znotraj selecta simulira if ukaz.

Sintaksa :

decode(polje,referenca,true,false)

primer:

select delavec,
sum(decode(mesec,1,ure,0)),sum(decode(mesec,2,ure,0),sum(decode(mesec,3,ure,0) ...

Ta primer že prikazuje rešitev, s tem, da je potrebno uporabiti grupno funkcijo, ki združi zapise na enega delavca

rezultat:

delavec 8 8 8 8 ...

Upam, da je primer dovolj razumljiv, kako pa to rešiti na drugih bazah, pa ne bi vedel, ker drugih baz ne poznam.
kdor zna pa žih

jerneju ::

hvala vam

zanima me samo se to, kako se nekemu datetimu pristeje en dan ali ena ura ali pa vec ur ali pa minut...

mercutio ::

Mislim, da je kar iščeš tole DATEADD.
Jah decode je pri Oraclu zelo uporaben ampak sam ne vem za ekvivalent pri MS SQL. Zato ti predlagam da napišeš User defined funkcijo (ki ti za datum in id_osebe vrne št. ur) in jo uporabiš v SQL stavku.

LP

jerneju ::

Tnx. Sem ze uporabil.

Drgač pa zdaj že deluje super, samo še na koncu moram vsoto dodat.
Sicer sem probal

1 + 2 +3 +... AS VSOTA
samo mi kar stevilke sesteje, ne pa pravih vrednosti u stolpcu, doh! Ma kdo kako idejo, kako to spremeniti?

Stevilke so namrec imena stolpcev.

Aja, pa še eno funkcijo iščem. Da preveri datetime. Npr. če obstaja 30. februar ali pa kaj podobnega. Ker imam narejeno, da mi od 1. pa do 31. dneva izpište. In včasih pride 31. dan že kar 3. dan v naslednjem mesecu, v tem primeru bi moral zadnje tri stolpce odrezat proč.

jerneju ::

Aja, za zadnji primer ze vem: CASE WHEN MONTH('02.27.2005 00:00:00')
= MONTH(DATEADD(day, 1, '02.27.2005 00:00:00'))
THEN 1 ELSE 0 END AS STATUS


Drugače me pa še zanima, kako ustvarim tabelo z dvema SELECToma.

Npr.

(SELECT blabla
+
SELECT blabla)

ORDER BY blablabla (pac oboje skupaj sortiram)

kopernik ::

Poglej si uporabo UNION. Unija dveh selectov. Mogoče se v MSSQL kako drugače kliče, ampak sigurno omogoča delo z množicami.

jerneju ::

Ja, uporabil sem UNION ALL. Tnx.

Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.


Tole mi javi strežnik sedaj, če ta select notri vtaknem. Okey, če dam za ene 10-15 dni v mesecu mi še deluje, za več pa sploh ne... Moram podaljšati čas, da bo pač strežnik imel na voljo več časa za pripravo vseh podatkov?

kopernik ::

indexi so ok postavljeni ?

kakšen je execution plan tvojih selectov ? če je preveč scanov celotnih tabel, potem bo potrebno optimizirati. Malo si poglej, kakšna orodja ponuja MS SQL za te zadeve. Jaz žal ne poznam MS SQL-a ...

Mimogrede, še vedno ti priporočam, če imaš kakšno možnost, te stvari reševati na nivoju aplikacije.

Zgodovina sprememb…

  • spremenil: kopernik ()

jerneju ::

Indexe sem sedaj spravil v red, aplikacija sedaj funkcionira.

Imam še eno preprosto vprašanje:

SELECT 1, 2
FROM (SELECT visina AS '1', globina AS '2'
FROM baza) tab

Napiše mi pa:

1 2
1 2
1 2
1 2


Kako naredim, da mi bo izpisal prave podatke, torej višino in globino?

Aja, kaj pa če bi rad seštel višino in globino, kako to naredim? 1 + 2, samo pol mi izpiše 3. Če pa dam '1' + '2' mi pa izpiše 12. ???

jerneju ::

Aja, če kdo slučajno ve...

Zanima me, kako v WHERE stavku dodam CASE...

Recimo

SELECT
blabla
from
blabla
where case when @nekaj=true then blabla


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

SQL query za datume, ki se ne prekrivajo

Oddelek: Programiranje
212625 (2256) omnimint
»

Statistika dijakov, pomoc

Oddelek: Programiranje
211794 (1278) Mitja Bonča
»

podatkovna baza

Oddelek: Programiranje
52061 (1882) scarymovie
»

SQL poizvedba

Oddelek: Programiranje
152172 (1682) borchi
»

[SQL] časovno obdobje

Oddelek: Programiranje
71400 (1228) R33D3M33R

Več podobnih tem