Diskuze: Složitý výběr
V předchozím kvízu, Online test znalostí SQL a databází, jsme si ověřili nabyté zkušenosti z kurzu.
Zobrazeno 6 zpráv z 6.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Online test znalostí SQL a databází, jsme si ověřili nabyté zkušenosti z kurzu.
Možná existuje lepší řešení, ale z první bych na to šel třeba takhle: zeptal bych se, kolik zařízení musí zbýt zaměstnanci půjčených (počet půjčení mínus počet vrácení pro dané zařízení), a do dočasné tabulky uložil právě tolik nejnovějších záznamů o výpůjčce. A takhle bych projel všechny zařízení cyklem (cursorem). Budu to psát pro MS-SQL, jinde se syntaxe může mírně lišit:
-- predpokladam, ze @EmployeeId bere procedura jako parametr
CREATE TABLE #Results
(
id INT,
device_id INT,
employee_id INT,
[date] DATETIME,
[state] VARCHAR(40),
protocol_number INT,
[transfer] BIT,
[name] VARCHAR(30),
serial_number VARCHAR(20),
inventory_number VARCHAR(6)
)
DECLARE @DeviceId INT
DECLARE C CURSOR READ_ONLY LOCAL FOR
SELECT DISTINCT device_id FROM Assigned_device WHERE employee_id = @EmployeeId
OPEN C
FETCH C INTO @DeviceId
WHILE (@@FETCH_STATUS = 0)
BEGIN
DECLARE @DeviceCount INT
SELECT @DeviceCount =
(SELECT COUNT(1) FROM Assigned_device WHERE device_id = @DeviceId AND employee_id = @EmployeeId AND [transfer] = 1)
- (SELECT COUNT(1) FROM Assigned_device WHERE device_id = @DeviceId AND employee_id = @EmployeeId AND [transfer] = 0)
INSERT INTO #Results (id, device_id, employee_id, [date], [state], protocol_number, [transfer], [name], serial_number, inventory_number)
SELECT TOP @DeviceCount
AD.id, AD.device_id, AD.employee_id, AD.[date], AD.[state], AD.protocol_number, AD.[transfer], D.[name], D.serial_number, D.inventory_number
FROM Assigned_device AD
LEFT OUTER JOIN Device D ON D.id = AD.device_id
WHERE AD.device_id = @DeviceId AND AD.employee_id = @EmployeeId AND AD.[transfer] = 1
ORDER BY AD.[date] DESC -- radit by slo i podle ad.id DESC
FETCH C INTO @DeviceId
END CLOSE C DEALLOCATE C
SELECT * FROM #Results
DROP TABLE #Results
Ahoj,
využij v dotazu case when then else end
Pujčil si (1) + vrátil (-1) tzn. už nemá (součet 0)
Dotaz bych postavil nějak takhle:
select * from (select device_id, empployee_id, sum(case when transfer = 1 then 1 else -1 end) Pocet
from [Assigned_device] with(nolock)
where empployee_id = 48
group by device_id, empployee_id) as tmpData inner join Device with(nolock) on tmpData.Device_ID = Device.ID
where tmpData.pocet > 0
Ppředpokládám, podle zápisu, že se jedná o MSSQL. To with(nolock)
znamená že čte bez zámků a i nedokončené transakce, je o dost
rychlejší, tady by dirty read vadit neměl
Podle mne to datum podstatne je. Ale ne teda pro forko.
Slo by resit tak, ze zarizeni i zamest. ma chip. Chipem si otevre dvere s naradim. Zarizeni projde dvernim ramem a zaeviduje zam-chip + naradi-chip, automaticky. Stale muze dojit k chybe. Ale aspon to nijak zvlast lidi neobtezuje.
Dalo by se to resit pres group by. Vyberes si 2 radky podle datumu, zarizeni + zapujceni, zarizeni + vraceni. A podle datumu urcit, zda schazi nebo je ve stavu vraceno, asi dalsim grupem. Ten dotaz jenom naznacim, zatim jsem nic takoveho neresil...
(
(
SELECT id_radek, id_zarizeni, datum
FROM tab
WHERE datum=MAX(datum)
GROUP BY id_zarizeni, stav
) -- to by melo vratit 2 radky, posledni vypujceni a vraceni pro kazde zarizeni
WHERE datum=MAX(datum)
GROUP BY id_zarizeni
) -- z toho vytridim posledni stav podle datumu
WHERE stav=0 (pujceno a nevraceno)
-- a nakonec vyberu podle stavu
Mozna to jde zjednodusit, vynechat nejaky krok.
Může existovat 5 půjčení a 2 vrácení, opačně ne. Nemůže vrátit něco co si nepůjčil. Jinak se jedná o MS-SQL. Zrovna zkouším vaše návrhy, tak dám vědět. Děkuji za rady. Jinak datum mám v tabulce vložený bez času a konkrétně deviceid132 byl zapůjčen dvakrát v jeden den v rámci jednoho protokolu. Čili zde nejde rozenat který byl dříve podle datumu ani času, ale jen podle id řádku v tabulce.
Zobrazeno 6 zpráv z 6.