Малко помощ диря....

14 отговора 523 прегледа
#1

Малко помощ диря....

щото нещо зациклих и съвсем изключих....
Та ....имам две таблици
1. Registry
ID | Name | FName |
-------------------------------
3076 Иван Иванов

PK = ID

2.Таблица Moves
ID | Year |
----------------------
3076 2003
3076 2002
3076 2001

PK = ID, Year ; FK=ID

С queryто ми получавам резултат:
3076, Иван, Иванов, 2003
3076, Иван, Иванов, 2002
3076, Иван, Иванов, 2001

А аз искам резултат от вида:
3076, Иван, Иванов, 2003,2002,2001

Отговор
в отговор на Aйeз Ceдaй #2

Re: Малко помощ диря....

Ами най накратко само със SQL може да се напише с много лефт джойнове, ама става грозно. Затова курсор, цикъл ...

Отговор
в отговор на Aйeз Ceдaй #3

Re: Малко помощ диря....

И как точно ти изглежда query-то?

So long and thanks for all the fish!
Отговор
в отговор на Пepин #4

Re: Малко помощ диря....

тц.
ще ми се да е с query, без курсор...тъпото е, че изтъпях тотално...
пробвах и със select case, ама мойто циклене си продължава.......... и пак достигам до резултата, който не ми върши работа...
затова иде реч за помощ....

Отговор
в отговор на hadministratora #5

Re: Малко помощ диря....

е то е ясно как...
въпросът ми е как да го докарам то резултатът, който искам или другото решение на проблема ми е от properties - Report builder - или на Repeating frame, или на field, но там четох хелпове и до никъде не стигнах.

Отговор
в отговор на hadministratora #6

Re: Малко помощ диря....

Абе куирито е сайдинска работа и е доста чийтване:



if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Moves]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[Moves]
GO

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Registry]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[Registry]
GO

CREATE TABLE [dbo].[Moves] (
[ID] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Yr] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]
GO

INSERT [Moves]([ID],[Yr]) VALUES('3076','2003')
INSERT [Moves]([ID],[Yr]) VALUES('3076','2002')
INSERT [Moves]([ID],[Yr]) VALUES('3076','2001')
INSERT [Moves]([ID],[Yr]) VALUES('3077','2000')
INSERT [Moves]([ID],[Yr]) VALUES('3077','2002')


CREATE TABLE [dbo].[Registry] (
[ID] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Name] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[FName] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]
GO

INSERT [Registry]([ID],[Name],[FName]) VALUES('3076','John','Doe')
INSERT [Registry]([ID],[Name],[FName]) VALUES('3077','Tim','Smith')


SELECT R.*, M1.Yr, M2.Yr, M3.Yr
FROM Registry AS R
LEFT OUTER JOIN Moves AS M1 ON
R.ID = M1.ID
AND M1.Yr IN (SELECT MAX (Yr) FROM Moves WHERE ID = M1.ID)
LEFT OUTER JOIN Moves AS M2 ON
R.ID = M2.ID
AND M2.Yr IN (SELECT MAX (Yr) FROM Moves WHERE ID = M2.ID AND Yr NOT IN (M1.Yr))
LEFT OUTER JOIN Moves AS M3 ON
R.ID = M3.ID
AND M3.Yr IN (SELECT MAX (Yr) FROM Moves WHERE ID = M3.ID AND Yr NOT IN (M1.Yr, M2.Yr))



Което дава:


ID Name FName Yr Yr Yr
---- ---- ----- ---- ---- ----
3076 John Doe 2003 2002 2001
3077 Tim Smith 2002 2000 NULL


Разбира се това с допускането че Moves има комплексен ключ (ID, Yr).
Представете си колко ме мързи да работя та седнах да напиша това.

Отговор
в отговор на Пepин #7

Re: Малко помощ диря....

Ех, Перине, Перине и тез жлъти очи...

не ми върши работа решението ти с дроп и инсерт и криейт тейбъл.. Нали се сещаш, че и двете таблици са доста по-сложни и имат сумати др. фк, които в случая не са съществени... (напр. ФК към таблицата дето записвам кой на коя дата, коя разписка и т.н си е платил даденото задължение. ) За всяка година за всеки ид има по един запис.

Отговор
в отговор на Aйeз Ceдaй #8

Re: Малко помощ диря....

Той Перина добре го е написал.
Ти гледай селекта. Другото е само скрипт за тестване
Кофтито е, че така става само ако предварително знаеш колко години ще имаш в един ред (max).
Иначе пътя "зациклих" е верния, но без "съвсем изключих"

Отговор
в отговор на Aйeз Ceдaй #9

Re: Малко помощ диря....

Кажи каква е базата поне?

И това "2003,2002,2001" в отделни колони ли го искаш, или като низ в една колона? Ако искаш да е в отделни, без динамичен SQL няма да минеш. Ако е като низ в една, може да се направи нещо по въпроса.

Отговор
в отговор на Aйeз Ceдaй #10

Re: Малко помощ диря....

ако кажеш че ти трябва за MySQL веднага мога да ти дам 2 решения за проблема

Отговор
в отговор на Aйeз Ceдaй #11

Re: Малко помощ диря....

Значи самото решение е само това:

SELECT R.*, M1.Yr, M2.Yr, M3.Yr
FROM Registry AS R
LEFT OUTER JOIN Moves AS M1 ON
R.ID = M1.ID
AND M1.Yr IN (SELECT MAX (Yr) FROM Moves WHERE ID = M1.ID)
LEFT OUTER JOIN Moves AS M2 ON
R.ID = M2.ID
AND M2.Yr IN (SELECT MAX (Yr) FROM Moves WHERE ID = M2.ID AND Yr NOT IN (M1.Yr))
LEFT OUTER JOIN Moves AS M3 ON
R.ID = M3.ID
AND M3.Yr IN (SELECT MAX (Yr) FROM Moves WHERE ID = M3.ID AND Yr NOT IN (M1.Yr, M2.Yr))

Другото е само за тестване. Не съм имал предвид че трябва да се изпълнява всеки път, нито че това трябва да е конкретната структура на таблиците.
БТВ с много лефт джойнове трябва да се внимава каква ще е производителността. Специално за SQL Server трябва да се напише като:

LEFT OUTER MERGE JOIN

иначе междинните резултати могат лесно да станат по няколко милиона реда.
Много поздрави на Амирлин , да и кажеш че не съм забравил че имам да я черпя едно кафе.

Отговор
в отговор на JohnT #12

Re: Малко помощ диря....

Би ли могъл да ги опишеш на кратко? Много ми е любопитно.

Отговор
в отговор на NDeu #13

Re: Малко помощ диря....

То реално погледнато даже с курсор да е, ако SQL-a не е динамичен няма как да върнеш променлив брой колони.
Мен друго ме притеснява в такъв род решения - масовото използване на леви джойнове може да доведе до катастрофално ниска производителност. Различните бази се опитват да оптимизират, ама обикновенно не се справят добре.
Курсорите по принцип са зло (и до колкото знам и на SQL Server и на Oracle) водят до създаване на темп таблица, но в случая мисля че са по-малкото зло.
Също и динамичен SQL си трябва да може да се определи верния брой колони.

Отговор
в отговор на Пepин #14

Re: Малко помощ диря....

IMHO, ако става въпрос за сложен анализ (OLAP) най добре е това да става на клиента, като необходимите данни се извличат от сървъра с прости селекти.
Ако е въпрос само за показване бих го направил (FB1.5) на сървъра в stored procedure, която да върне във varchar списъка на годините с някакъв разделител. В този случай няма да ми се наложи даже да правя динамичен SQL.

CREATE PROCEDURE LIST_OF_YEARS
RETURNS (
ID INTEGER,
NAME VARCHAR(50),
FNAME VARCHAR(50),
YEARS VARCHAR(1024))
AS
DECLARE VARIABLE YR VARCHAR(1024);
begin
for select ID,Name,FName
from registry
into :id, :name,:fname
do begin
Years='';
for select Yr
from moves
where ID=:id
order by YR
into :YR
do Years=:years||:YR||',';
suspend;
end
end


Отговор
в отговор на NDeu #15

Re: Малко помощ диря....

> ако става въпрос за сложен анализ (OLAP) най добре е това да
> става на клиента, като необходимите данни се извличат от
> сървъра с прости селекти.

Не ми се ще да давам съвети без да знам изскванията, ама съм 99% сигурен че Year би било едно от измеренията. Съответно OLAP клиента ще работи с него като с всяко друго измерение, включително ще може да подрежда различните стойности на измерението по колони вместо редове.

Отговор