Помогите с SQL-запросом!
От: corpse56  
Дата: 30.06.09 13:38
Оценка:
Здравствуйте!
вот есть такой запрос:

select 
case when (tmp.MNFIELD = 200 and tmp.MSFIELD = '$a') then tmp.PLAIN end as zagl,
case when (tmp.MNFIELD = 700 and tmp.MSFIELD = '$a') then tmp.PLAIN end as avtor,
case when (tmp.MNFIELD = 899 and tmp.MSFIELD = '$p') then tmp.PLAIN end as inv,
 from
(
select A.SORT, B.PLAIN, A.MSFIELD, A.MNFIELD, B.IDMAIN

 from DATAEXTPLAIN B
 join DATAEXT A on A.ID=B.IDDATAEXT and A.IDMAIN=B.IDMAIN

where 
( (
or (A.MNFIELD = 200 and A.MSFIELD = '$a') --заглавие
or (A.MNFIELD = 700 and A.MSFIELD = '$a') --автор
or (A.MNFIELD = 899 and A.MSFIELD = '$p') --инв.номер
) 
 and B.IDMAIN =654135) --необходимый экземпляр книги
) as tmp



таблицы dataext и dataextplain имеют следующую структуру.
в dataext содержится поле SORT в котором в каждой записи идут подряд разные логические поля (заглавие, автор, место издания и т.д.). о том какое именно это логическое поле можно узнать по двум физическим полям MSFIELD и MNFIELD. (как видно из примера если MNFIELD = 200 а MSFIELD = '$a', то это заглавие). поле SORT предназначено для того чтоб сортировать по этому полю. оно не содержит пробелов знаков препинания и т.д. для того чтобы увидеть как полностью должно выглядеть значение поля, в dataext связано с dataextplain (DATAEXT.ID=DATAEXTPLAIN.IDDATAEXT) в котором полная версия поля.
вопрос в том чтобы выудить из этих таблиц данные о книге в привычном так сказать формате. т.е. не все поля вперемешку в один столбик, а по разным столбикам (а то на клиенте через чур долго это делать, хоть и не при моих объемах, но думаю что лучше если это сервер сделает). мой пример не так работает как я хотел бы. я хотел бы получить стока строк про книгу скока инвентарей есть на эту книгу и пусть остальные поля повторятся.ну вот например:
DATAEXT выглядит так:
ID....SORT.......MNFIELD........MSFIELD...IDMAIN
------------------------------------------------
1......A..........200............$a........1
2......AA.........700............$a........1
3......11.........899............$p........1
4......21.........899............$p........1
5......31.........899............$p........1
6......B..........200............$a........2
7......BB.........700............$a........2
8......41.........899............$p........2
9......51.........899............$p........2
10.....С..........200............$a........3
11.....СС.........700............$a........3
12.....51.........899............$p........3
-------------------------------------------------
DATAEXTPLAIN выглядит так:
ID....PLAIN........IDMAIN.....IDDATAEXT
---------------------------------------
1......51............3...........12
2......С,С...........3...........11
3......С.............3...........10
4......51............2...........9
5......41............2...........8
6......B,B...........2...........7
7......B.............2...........6
8......31............1...........5
9......21............1...........4
10.....11............1...........3
11.....A,A...........1...........2
12.....A.............1...........1
---------------------------------------

получить хочу вот так:

zag.....avtor.....inv....IDMAIN
-------------------------------
A.......AA........11......1
A.......AA........21......1
A.......AA........31......1
B.......BB........41......2
B.......BB........51......2
C.......CC........61......3
-------------------------------

или вот так:
zag.....avtor...IDMAIN
----------------------
A.......AA.......1
B.......BB.......2
C.......CC.......3
----------------------

а получаю вот так:
zag.....avtor.....inv......IDMAIN
---------------------------------
A.......NULL......NULL.....1
NULL....AA........NULL.....1
NULL....NULL......11.......1
NULL....NULL......21.......1
NULL....NULL......31.......1
NULL....BB........NULL.....2
B.......NULL......NULL.....2
NULL....NULL......41.......2
NULL....NULL......51.......2
--------------------- и так далее


кстати еще вопрос: как лучше получать? с инвентарями и потом их доставать из DataSet или без инвентарей и запрашивать каждый раз? наверное все таки с инвентарями. лучше немного избыточности, чем потом еще кучу запросов к базе...
а можете есть лучше способ? что-то типа поле-массив? чувствую что нет такого...
спасибо. если что-то не понятно, спрашивайте — я уточню.


для простоты положим что для описания книги нужно всего три поля которые указаны в запросе: заглавие, автор, инвентарный номер.
заглавие и автор для экземпляра книги встречаются один раз, а инвентарей может быть несколько.

спасибо что дочитали до сюда. всю голову сломал — помогите!
Re: Помогите с SQL-запросом!
От: FilosOFF Россия  
Дата: 30.06.09 14:24
Оценка:
Здравствуйте, corpse56, Вы писали:

Что за БД?
... << RSDN@Home 1.2.0 alpha 4 rev. 1231>>
Re[2]: Помогите с SQL-запросом!
От: corpse56  
Дата: 30.06.09 14:48
Оценка:
Здравствуйте, FilosOFF, Вы писали:

FOF>Что за БД?


MS SQL 2005
Re[3]: Помогите с SQL-запросом!
От: FilosOFF Россия  
Дата: 01.07.09 09:24
Оценка: 3 (1)
Здравствуйте, corpse56, Вы писали:

C>MS SQL 2005


ну гдето так:

CREATE TABLE #DATAEXT
(
    ID       INT IDENTITY(1, 1),
    SORT     NVARCHAR(5),
    MNFIELD  NVARCHAR(5),
    MSFIELD  NVARCHAR(5),
    IDMAIN   INT
)
 
INSERT INTO #DATAEXT
  (
    SORT,
    MNFIELD,
    MSFIELD,
    IDMAIN
  )
SELECT 'A','200','$a',1
UNION ALL
SELECT 'AA','700','$a',1
UNION ALL
SELECT '11','899','$p',1
UNION ALL
SELECT '21','899','$p',1
UNION ALL
SELECT '31','899','$p',1
UNION ALL
SELECT 'B','200','$a',2
UNION ALL
SELECT 'BB','700','$a',2
UNION ALL
SELECT '41','899','$p',2
UNION ALL
SELECT '51','899','$p',2
UNION ALL
SELECT 'С','200','$a', 3
UNION ALL
SELECT 'СС','700','$a',3
UNION ALL
SELECT '51','899','$p',3
 
CREATE TABLE #DATAEXTPLAIN
(
    ID         INT IDENTITY(1, 1),
    PLAIN      NVARCHAR(5),
    IDMAIN     INT,
    IDDATAEXT  INT
)
     
INSERT INTO #DATAEXTPLAIN
  (
    PLAIN,
    IDMAIN,
    IDDATAEXT
  )
SELECT '51',3,12
UNION ALL
SELECT 'С,С',3,11
UNION ALL
SELECT 'С',3,10
UNION ALL
SELECT '51',2,9
UNION ALL
SELECT '41',2,8
UNION ALL
SELECT 'B,B',2,7
UNION ALL
SELECT 'B',2,6
UNION ALL
SELECT '31',1,5
UNION ALL
SELECT '21',1,4
UNION ALL
SELECT '11',1,3
UNION ALL
SELECT 'A,A',1,2
UNION ALL
SELECT 'A',1,1;
  
    WITH FC AS (SELECT dt.ID,
                       dt.MNFIELD,
                       dt.MSFIELD,
                       dt.IDMAIN,
                       dtp.PLAIN
                FROM   #DATAEXT dt
                       JOIN #DATAEXTPLAIN dtp
                            ON  dt.ID = dtp.IDDATAEXT)
SELECT COL1.PLAIN,
       COL2.PLAIN,
       COL3.PLAIN
FROM   FC COL1
       JOIN FC AS COL2
            ON  COL2.IDMAIN = COL1.IDMAIN
                AND COL2.MNFIELD = 700
                AND COL2.MSFIELD = '$a'
       JOIN FC AS COL3
            ON  COL3.IDMAIN = COL1.IDMAIN
                AND COL3.MNFIELD = 899
                AND COL3.MSFIELD = '$p'
WHERE  COL1.MNFIELD = 200
       AND COL1.MSFIELD = '$a'
ORDER BY
       COL1.PLAIN,
       COL3.PLAIN
   
DROP TABLE #DATAEXT
DROP TABLE #DATAEXTPLAIN


Пойдет?

P.S. Очень муторно таблички тест. данными забивать
... << RSDN@Home 1.2.0 alpha 4 rev. 1231>>
Re[4]: Помогите с SQL-запросом!
От: corpse56  
Дата: 01.07.09 14:07
Оценка:
Здравствуйте, FilosOFF, Вы писали:


FOF>Пойдет?


это просто супер! именно то что нужно! спасибо!
Re[4]: Помогите с SQL-запросом!
От: corpse56  
Дата: 03.07.09 12:45
Оценка:
Здравствуйте, FilosOFF, Вы писали:

FOF>Пойдет?


задача усложняется.
DATAEXT выглядит так:
ID....SORT.......MNFIELD........MSFIELD...IDMAIN........IDDATA
--------------------------------------------------------------
1......A..........200...............$a...........1.............1
2......AA.........700...............$a...........1.............2
3......11.........899...............$p...........1.............3
4......21.........899...............$p...........1.............4
5......сп.........929...............$b...........1.............4
6......31.........899...............$p...........1.............5
7......B..........200...............$a...........2.............6
8......BB.........700...............$a...........2.............7
9......сп.........929...............$b...........2.............8
10.....41.........899...............$p...........2.............9
11.....51.........899...............$p...........2.............8
12.....NY.........210...............$a...........2.............10
13.....AM.........210...............$a...........2.............11
14.....С..........200...............$a...........3.............12
15.....СС.........700...............$a...........3.............13
16.....61.........899...............$p...........3.............14
17.....сп.........929...............$b...........1.............5
18.....СВ.........210...............$a...........1.............15
--------------------------------------------------------------

добавилась строка 5 и 9. они означают что инвентари 21 и 51 соответственно списаны. вот их и нужно выбрать!
добавилась колонка IDDATA. из её функций я знаю только одну — с помощью нее можно установить какой именно инвентарь списан.

DATAEXTPLAIN выглядит так:
ID....PLAIN........IDMAIN.....IDDATAEXT
---------------------------------------
1......61............3...........14
2......С,С...........3...........13
3......С.............3...........12
4......A,M...........2...........11
5......N,Y...........2...........10
6......51............2...........9
7......41............2...........8
8......B,B...........2...........7
9......B.............2...........6
10......31...........1...........5
11......21...........1...........4
12.....11............1...........3
13.....A,A...........1...........2
14.....A.............1...........1
15.....с,п...........1...........5
16.....с,п...........2...........9
17.....с,п...........1...........17
18.....С,В...........1...........18
---------------------------------------

получить хочу вот так:

zag.....avtor.....inv....IDMAIN.......cnt......mizd
-----------------------------------------------------
A.......AA........11......1............2..........С,В
A.......AA........21......1............2..........С,В
B.......BB........51......2............1..........N,YA,M
------------------------------------------------------ //строка СС не выбирается, т.к. экземпляры этой книги не списывались.

cnt — вычисляемое поле, которое вычисляет разницу между количеством инвентарей и количеством списанных инвентарей.

второе усложнение вот в чем. для каждой книги есть мето издания.(в моем примере не для каждой а только для книги с IDMAIN = 1 или 2). так вот если место издания одно — то Ваш запрос срабатывает. Но бывает так, что мест изданий 2 или больше. в этом случае необходимо чтобы в колонке место издания отображалась конкатенация всех изданий. я признаться даже не знаю как в терминах sql складывать строки и получать из них новую колонку...
я весь запутался. и пока вопрос писал — еще больше запутался. если какие-то уточнения необходимы — спрашивайте — я мог что-то упустить при упрощениях.
подскажите пожалуйста, как сие реализовать? в том что это возможно, сомнений нет, но целесообразно ли это? может эту "байду" лучше на клиенте делать?
спасибо.
Re[5]: Помогите с SQL-запросом!
От: FilosOFF Россия  
Дата: 06.07.09 08:49
Оценка:
Здравствуйте, corpse56, Вы писали:

C>Здравствуйте, FilosOFF, Вы писали:


FOF>>Пойдет?


C>задача усложняется.


C>добавилась строка 5 и 9. они означают что инвентари 21 и 51 соответственно списаны. вот их и нужно выбрать!

C>добавилась колонка IDDATA. из её функций я знаю только одну — с помощью нее можно установить какой именно инвентарь списан.

1. Я уже пытался намекнуть что данные лучше подготовить в виде:
CREATE TABLE #DATAEXT
(
    ID       INT IDENTITY(1, 1),
    SORT     NVARCHAR(5),
    MNFIELD  NVARCHAR(5),
    MSFIELD  NVARCHAR(5),
    IDMAIN   INT
)
 
INSERT INTO #DATAEXT
  (
    SORT,
    MNFIELD,
    MSFIELD,
    IDMAIN
  )
SELECT 'A','200','$a',1
UNION ALL
SELECT 'AA','700','$a',1
UNION ALL

Чтобы было о чем говорить, не тратя время на создание табличек

2. Т.е. надо выбрать те книги у которых есть записи с "929...............$b"? Ну дык Exists Вам в помощь.



C>cnt — вычисляемое поле, которое вычисляет разницу между количеством инвентарей и количеством списанных инвентарей.

3. Вот это совершенно не понял.

C>второе усложнение вот в чем. для каждой книги есть мето издания.(в моем примере не для каждой а только для книги с IDMAIN = 1 или 2). так вот если место издания одно — то Ваш запрос срабатывает. Но бывает так, что мест изданий 2 или больше. в этом случае необходимо чтобы в колонке место издания отображалась конкатенация всех изданий. я признаться даже не знаю как в терминах sql складывать строки и получать из них новую колонку...

C>я весь запутался. и пока вопрос писал — еще больше запутался. если какие-то уточнения необходимы — спрашивайте — я мог что-то упустить при упрощениях.
C>подскажите пожалуйста, как сие реализовать? в том что это возможно, сомнений нет, но целесообразно ли это? может эту "байду" лучше на клиенте делать?
C>спасибо.
Вот будут данные, тогда и посмотрим.
... << RSDN@Home 1.2.0 alpha 4 rev. 1231>>
Re[6]: Помогите с SQL-запросом!
От: corpse56  
Дата: 06.07.09 15:29
Оценка:
Здравствуйте, FilosOFF, Вы писали:

FOF>1. Я уже пытался намекнуть что данные лучше подготовить в виде:



CREATE TABLE #DATAEXTdem
(
    ID       INT IDENTITY(1, 1),
    SORT     NVARCHAR(5),
    MNFIELD  NVARCHAR(5),
    MSFIELD  NVARCHAR(5),
    IDMAIN   INT,
    IDDATA     INT
)
 
INSERT INTO #DATAEXTdem
  (
    SORT,
    MNFIELD,
    MSFIELD,
    IDMAIN,
    IDDATA
  )
SELECT 'A','200','$a',1,1
UNION ALL
SELECT 'AA','700','$a',1,2
UNION ALL
SELECT '11','899','$p',1,3
UNION ALL
SELECT '21','899','$p',1,4
UNION ALL
SELECT 'sp','929','$b',1,4
UNION ALL
SELECT '31','899','$p',1,5
UNION ALL
SELECT 'B','200','$a',2,6
UNION ALL
SELECT 'BB','700','$a',2,7
UNION ALL
SELECT 'sp','929','$b',2,8
UNION ALL
SELECT '41','899','$p',2,9
UNION ALL
SELECT '51','899','$p',2,8
UNION ALL
SELECT 'NY','210','$a',2,10
UNION ALL
SELECT 'AM','210','$a',2,11
UNION ALL
SELECT 'C','200','$a',3,12
UNION ALL
SELECT 'CC','700','$a',3,13
UNION ALL
SELECT '61','899','$p',3,14
UNION ALL
SELECT 'CB','210','$a',1,15


CREATE TABLE #DATAEXTPLAINdem
(
    ID        INT IDENTITY(1, 1),
    PLAIN     NVARCHAR(5),
    IDMAIN    INT,
    IDDATAEXT INT
)
 
INSERT INTO #DATAEXTPLAINdem
  (
    PLAIN,
    IDMAIN,
    IDDATAEXT
  )
SELECT '61',3,14
UNION ALL
SELECT 'C,C',3,13
UNION ALL
SELECT 'C',3,12
UNION ALL
SELECT 'A,M',2,11
UNION ALL
SELECT 'N,Y',2,10
UNION ALL
SELECT '51',2,9
UNION ALL
SELECT '41',2,8
UNION ALL
SELECT 'B,B',2,7
UNION ALL
SELECT 'B',2,6
UNION ALL
SELECT '31',1,5
UNION ALL
SELECT '21',1,4
UNION ALL
SELECT '11',1,3
UNION ALL
SELECT 'A,A',1,2
UNION ALL
SELECT 'A',1,1
UNION ALL
SELECT 's,p',3,9
UNION ALL
SELECT 's,p',1,4
UNION ALL
SELECT 'C,B',3,18


FOF>2. Т.е. надо выбрать те книги у которых есть записи с "929...............$b"? Ну дык Exists Вам в помощь.

не совсем, но суть в этом. 929..$b означает что инвентарь списан.
например есть строки
SELECT '21','899','$p',1,4
SELECT '11','899','$p',1,3
SELECT '31','899','$p',1,5
SELECT 'sp','929','$b',1,4

это означает что, что у книги с IDMAIN = 1 есть три экземпляра (три инвентарных номера 11,21 и 31).
строка с 929..$b означает что какой-то инвентарь списан. какой? ответ в последней колонке (4). т.е. 929..$b относится к инвентарю 21. т.к. значения последнего столбика у них совпадают.

C>>cnt — вычисляемое поле, которое вычисляет разницу между количеством инвентарей и количеством списанных инвентарей.

FOF>3. Вот это совершенно не понял.
для книги с IDMAIN = 1 есть 3 экземпляра. списан 1 экземпляр. cnt = 3 — 1 = 2. т.е. количество оставшихся экземпляров.
в предыдущем посте я ошибся в таблице которую хотел получить. теперь надеюсь все доглядел:


zag.....avtor.....invsp....IDMAIN.......cnt......mizd..........invremain
------------------------------------------------------------------------
A.......AA........21......1............2..........С,В..........11,31
B.......BB........51......2............1..........N,Y;A,M.......41
------------------------------------------------------------------------
книга с IDMAIN = 3 не выбирается, потому что у ней нету списанных инвентарей.
у одной книги мест издания(mizd) может быть 2 и больше (не спрашивайте почему), а может быть так что и совсем нету (просто такой строчки 210...$a для книги не существует). в случае если их 2 и больше, они через точку запятой конкатенируются.
оставшиеся инвентари(invremain), которые не списаны,т.е. для которых не существует строки 929...$b, конкатенируются через запятую.

подскажите, пожалуйста!
спасибо!
Re[7]: Помогите с SQL-запросом!
От: FilosOFF Россия  
Дата: 07.07.09 07:59
Оценка: 3 (1)
Здравствуйте, corpse56, Вы писали:

1. Для начала у Вас не совсем корректные данные Есть не соответствие:
SELECT 'CB','210','$a',1,15
А вот
Записи в табличке #DATAEXTPLAINdem c IDDATAEXT = 15 Нетути.


  WITH FC AS (SELECT dt.ID,
                      dt.MNFIELD,
                      dt.MSFIELD,
                      dt.IDMAIN,
                      dtp.PLAIN
               FROM   #DATAEXT dt
                      JOIN #DATAEXTPLAIN dtp
                           ON  dt.IDDATA = dtp.IDDATAEXT),
                            
   GC AS (SELECT COL1.PLAIN AS ZAG,
                 COL2.PLAIN AS AVT,
                 COL3.PLAIN AS INV,
                 COL4.PLAIN AS MIZD,
                 COL1.IDMAIN,
                 DENSE_RANK() OVER(ORDER BY COL1.IDMAIN, COL4.PLAIN) AS GN
          FROM   FC COL1
                 LEFT JOIN FC AS COL2
                      ON  COL2.IDMAIN = COL1.IDMAIN
                          AND COL2.MNFIELD = 700
                          AND COL2.MSFIELD = '$a'
                 LEFT JOIN FC AS COL3
                      ON  COL3.IDMAIN = COL1.IDMAIN
                          AND COL3.MNFIELD = 899
                          AND COL3.MSFIELD = '$p'
                 LEFT JOIN FC AS COL4
                      ON  COL4.IDMAIN = COL1.IDMAIN
                          AND COL4.MNFIELD = 210
                          AND COL4.MSFIELD = '$a'
          WHERE  COL1.MNFIELD = 200
                 AND COL1.MSFIELD = '$a'
                 AND EXISTS(SELECT 1
                            FROM   FC COL4
                            WHERE  COL4.MNFIELD = 929
                                   AND COL4.MSFIELD = '$b'
                                   AND COL1.IDMAIN = COL4.IDMAIN)),
                                          
FG AS (SELECT ZAG,
              AVT,
              INV,
              MIZD,
              CAST(MIZD AS VARCHAR(20)) AS FIZD,
              1 AS COLIZD,
              IDMAIN,
              GN
       FROM   GC A1
       WHERE  GN = (SELECT MIN(GN)
                    FROM   GC A2
                    WHERE  A2.IDMAIN = A1.IDMAIN
                           AND A2.INV = A1.INV)
       UNION ALL 
       SELECT A1.ZAG,
              A1.AVT,
              A1.INV,
              A2.MIZD,
              CAST(A1.MIZD + '/' + A2.MIZD AS VARCHAR(20)) AS FIZD,
              (A1.COLIZD + 1) AS COLIZD,
              A1.IDMAIN,
              A2.GN
       FROM   FG A1
              JOIN GC A2
                   ON  A2.IDMAIN = A1.IDMAIN
                       AND A2.INV = A1.INV
       WHERE  A1.GN < A2.GN)
SELECT ZAG,
       AVT,
       FIZD,
       INV
FROM   FG A1
WHERE  COLIZD = (SELECT MAX(COLIZD)
                 FROM   FG A2
                 WHERE  A2.IDMAIN = A1.IDMAIN
                        AND A2.INV = A1.INV)


2. В запросе есть строчка:
AND EXISTS(SELECT 1
                            FROM   FC COL4
                            WHERE  COL4.MNFIELD = 929
                                   AND COL4.MSFIELD = '$b'
                                   AND COL1.IDMAIN = COL4.IDMAIN)

Она отбирает те IDMAIN у которых есть удаленные инв.
В общем играя с этим вы получите и удаленные и не удаленные.
Собственно используя это, можно легко посчитать кол-во одних и кол-во других Это к разнице.
Ну а в третьих, это пипец. Меняйте структуру таблиц.
... << RSDN@Home 1.2.0 alpha 4 rev. 1231>>
Re[8]: Помогите с SQL-запросом!
От: corpse56  
Дата: 09.07.09 07:39
Оценка:
Здравствуйте, FilosOFF, Вы писали:

Спасибо огромное! это именно то что я хотел!ура!


FOF>1. Для начала у Вас не совсем корректные данные Есть не соответствие:

FOF>SELECT 'CB','210','$a',1,15
FOF>А вот
FOF>Записи в табличке #DATAEXTPLAINdem c IDDATAEXT = 15 Нетути.

извиняюсь. я там вообще все напутал... но смог поправить теперь все именно так как я хочу.

IDDATA — это НЕ стобец ID в таблице DATAEXT. стобец ID в DATAEXT это столбец IDDATAEXT в таблице DATAEXTPLAIN. Столбец IDDATA помогает нам узанть к какому именно инвентарю отностится 929..$b, т.е. какой именно инвентарь списан. и этот столбец не имеет отношения к таблице DATAEXTPLAIN. это я упустил, за что и извиняюсь. я когда начал делать таблицы с помощью UNION SELECT немного запутался и забыл переставить строки так чтобы столбец IDDATAEXT соответствовал ключу таблицы DATAEXT. к счастью это не сильно повлияло и я смог переделать запрос. если интересно вот что получилось:


CREATE TABLE #DATAEXTdem
(
    ID       INT IDENTITY(1, 1),
    SORT     NVARCHAR(5),
    MNFIELD  NVARCHAR(5),
    MSFIELD  NVARCHAR(5),
    IDMAIN   INT,
    IDDATA     INT
)
 
INSERT INTO #DATAEXTdem
  (
    SORT,
    MNFIELD,
    MSFIELD,
    IDMAIN,
    IDDATA
  )
SELECT 'A','200','$a',1,1
UNION ALL
SELECT 'AA','700','$a',1,2
UNION ALL
SELECT '11','899','$p',1,3
UNION ALL
SELECT '21','899','$p',1,4
UNION ALL
SELECT 'sp','929','$b',1,4
UNION ALL
SELECT '31','899','$p',1,5
UNION ALL
SELECT 'B','200','$a',2,6
UNION ALL
SELECT 'BB','700','$a',2,7
UNION ALL
SELECT 'sp','929','$b',2,8
UNION ALL
SELECT '41','899','$p',2,9
UNION ALL
SELECT '51','899','$p',2,8
UNION ALL
SELECT 'NY','210','$a',2,10
UNION ALL
SELECT 'AM','210','$a',2,11
UNION ALL
SELECT 'C','200','$a',3,12
UNION ALL
SELECT 'CC','700','$a',3,13
UNION ALL
SELECT '61','899','$p',3,14
UNION ALL
SELECT 'CB','210','$a',1,15


CREATE TABLE #DATAEXTPLAINdem
(
    ID        INT IDENTITY(1, 1),
    PLAIN     NVARCHAR(5),
    IDMAIN    INT,
    IDDATAEXT INT
)
 
INSERT INTO #DATAEXTPLAINdem
  (
    PLAIN,
    IDMAIN,
    IDDATAEXT
  )
SELECT 'A',1,1
UNION ALL
SELECT 'A,A',1,2
UNION ALL
SELECT '11',1,3
UNION ALL
SELECT '21',1,4
UNION ALL
SELECT 's,p',1,5
UNION ALL
SELECT '31',1,6
UNION ALL
SELECT 'B',2,7
UNION ALL
SELECT 'B,B',2,8
UNION ALL
SELECT 's,p',3,9
UNION ALL
SELECT '41',2,10
UNION ALL
SELECT '51',2,11
UNION ALL
SELECT 'N,Y',2,12
UNION ALL
SELECT 'A,M',2,13
UNION ALL
SELECT 'C',3,14
UNION ALL
SELECT 'C,C',3,15
UNION ALL
SELECT '61',3,16
UNION ALL
SELECT 'C,B',3,17;

WITH FC AS (SELECT dt.ID,
                      dt.MNFIELD,
                      dt.MSFIELD,
                      dt.IDMAIN,
                      dt.IDDATA,    
                      dtp.PLAIN
               FROM   #DATAEXTdem dt
                      JOIN #DATAEXTPLAINdem dtp
                           ON  dt.ID = dtp.IDDATAEXT),
                            
   GC AS (SELECT COL1.PLAIN AS ZAG,
                 COL2.PLAIN AS AVT,
                 COL3.PLAIN AS INV,
                 COL4.PLAIN AS MIZD,
                 COL1.IDMAIN,
                 DENSE_RANK() OVER(ORDER BY COL1.IDMAIN, COL4.PLAIN) AS GN
          FROM   FC COL1
                 LEFT JOIN FC AS COL2
                      ON  COL2.IDMAIN = COL1.IDMAIN
                          AND COL2.MNFIELD = 700
                          AND COL2.MSFIELD = '$a'
                 LEFT JOIN FC AS COL3
                      ON  COL3.IDMAIN = COL1.IDMAIN
                          AND COL3.MNFIELD = 899
                          AND COL3.MSFIELD = '$p'
                 LEFT JOIN FC AS COL4
                      ON  COL4.IDMAIN = COL1.IDMAIN
                          AND COL4.MNFIELD = 210
                          AND COL4.MSFIELD = '$a'
          WHERE  COL1.MNFIELD = 200
                 AND COL1.MSFIELD = '$a'
                 AND EXISTS(SELECT 1
                            FROM   FC COL4
                            WHERE  COL4.MNFIELD = 929
                                   AND COL4.MSFIELD = '$b'
                                   AND COL4.IDDATA = COL3.IDDATA)
),
                                          
FG AS (SELECT ZAG,
              AVT,
              INV,
              MIZD,
              CAST(MIZD AS VARCHAR(20)) AS FIZD,
              1 AS COLIZD,
              A1.IDMAIN,
              GN
       FROM   GC A1 --join cnt on A1.IDMAIN=cnt.IDMAIN
       WHERE  GN = (SELECT MIN(GN)
                    FROM   GC A2
                    WHERE  A2.IDMAIN = A1.IDMAIN
                           AND A2.INV = A1.INV)
       UNION ALL 
       SELECT A1.ZAG,
              A1.AVT,
              A1.INV,
              A2.MIZD,
              CAST(A1.MIZD + '/' + A2.MIZD AS VARCHAR(20)) AS FIZD,
              (A1.COLIZD + 1) AS COLIZD,
              A2.IDMAIN,
              A2.GN
       FROM   FG A1
              JOIN GC A2
                   ON  A2.IDMAIN = A1.IDMAIN
                       AND A2.INV = A1.INV
       WHERE  A1.GN < A2.GN),

cnt as (SELECT COL5.IDMAIN as idm,count(COL6.IDMAIN) as koli
        FROM   FC COL5
                JOIN FC AS COL6 ON  COL5.IDMAIN = COL6.IDMAIN

                            WHERE  not exists (SELECT 1
                            FROM    FC COL7
                            WHERE COL7.MNFIELD = 929
                                   AND COL7.MSFIELD = '$b'
                   AND COL7.IDDATA = COL6.IDDATA)
                               
                   AND COL5.MNFIELD = 899
                                   AND COL5.MSFIELD = '$p'
                   AND COL5.PLAIN = COL6.PLAIN
        group by COL5.IDMAIN)

SELECT IDMAIN
       ZAG,
       AVT,
       FIZD,
       INV,cnt.koli
FROM   FG A1 join cnt on A1.IDMAIN=cnt.idm
WHERE  COLIZD = (SELECT MAX(COLIZD)
                 FROM   FG A2
                 WHERE  A2.IDMAIN = A1.IDMAIN
                        AND A2.INV = A1.INV)

DROP TABLE #DATAEXTdem
DROP TABLE #DATAEXTPLAINdem

я добавил cnt для подсчета количества экземпляров книги, которые не списаны.
Спасибо Вам огромное . сколько же нужно работать чтоб такие запросы щелкать как орехи? не представляю..


FOF>Ну а в третьих, это пипец. Меняйте структуру таблиц.


не. эту систему уже 3 года разрабатывают и точно базу данных не будут менять. а я пишу небольшие вспомагательные программки.так сделано специально, чтобы если меняется структура, то количество полей не меняется, а добавляются только новые записи.
Re[9]: Помогите с SQL-запросом!
От: FilosOFF Россия  
Дата: 09.07.09 08:11
Оценка:
Здравствуйте, corpse56, Вы писали:

C>я добавил cnt для подсчета количества экземпляров книги, которые не списаны.

C>Спасибо Вам огромное . сколько же нужно работать чтоб такие запросы щелкать как орехи? не представляю..
Рад что моя голова оказалась полезной.
9 лет комерческой разработки больших систем, от ERP до промышленных систем контроля производства.


FOF>>Ну а в третьих, это пипец. Меняйте структуру таблиц.


C>не. эту систему уже 3 года разрабатывают и точно базу данных не будут менять. а я пишу небольшие вспомагательные программки.так сделано специально, чтобы если меняется структура, то количество полей не меняется, а добавляются только новые записи.


Ну мож так и надо...
... << RSDN@Home 1.2.0 alpha 4 rev. 1231>>
Re[9]: Помогите с SQL-запросом!
От: corpse56  
Дата: 09.07.09 14:50
Оценка:
эмм... я тут подзавис немного. что нужно добавить в запрос, если у меня есть еще поля типа FIZD?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.