SQL - перебирая столбцы, когда найден пустой, обновите его - PullRequest
0 голосов
/ 26 июля 2010

Я запустил аналогичную ветку, но поскольку проблема сложнее, я хотел бы начать с нуля.
Представьте, что есть 10 слотов инвентаря (в БД это столбцы в строке пользователя). Когда пользователь поднимает элемент, он должен быть помещен в первый пустой столбец (он обновляется). Но как сделать цикл по столбцам (кроме IF EXISTS) в запросе, если я хочу иметь еще гибкий дизайн? Это не может быть решено хорошо, если элементы расположены в строках, так как порядок элементов имеет значение (каждый элемент принадлежит определенной ячейке) Если у пользователей заполнены 1-й и 3-й слоты, следующий выбранный элемент должен перейти во 2-й. Надеюсь, теперь все понятно, спасибо!

Ответы [ 4 ]

1 голос
/ 26 июля 2010

Почему бы просто не иметь еще одну таблицу для предметов инвентаря? Таким образом, у вас будет таблица инвентаря и таблица инвентаризации, например:

----------
inventory
----------
id int
description varchar(100)

---------------
inventory_item
---------------
id  int
inventory_id int (foreign key to inventory table)
sequence_num int (indicates which "slot" the data represents)

Итак, теперь у вас может быть строка в инвентаре, а затем вы можете вставить строки в inventory_item, когда получите значения. Поэтому, если у вас есть 3 значения, вы просто вставили бы 3 строки в inventory_item. Что касается того, в какой «слот» они входят, поле sequence_num сообщит вам об этом.

EDIT
Чтобы запросить существующие инвентаризационные элементы для определения следующего доступного номера слота, вы можете сделать что-то вроде:

SELECT coalesce(MAX(sequence_num),0) + 1 next_sequence_num
  FROM inventory_item
 WHERE inventory_id = xxx

Если нет инвентаризационных элементов, это вернет 1. Если существующие предметы присутствуют, это даст вам следующий «номер слота» для использования (я называю это sequence_number, но то же самое).

1 голос
/ 26 июля 2010

Вы нарушаете 1NF, делая это таким образом, и именно поэтому вы сталкиваетесь с этой проблемой.

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

Я не уверен, к чему относится Inventoryslot в вашем примере, но таблица должна выглядеть примерно так.

InventorySlots(InventorySlotId, RelatedFieldID, OrderNumber, ItemID)

Вы можете поместить индекс UNIQUE в RelatedFieldID и OrderNumber, чтобы предотвратить два элемента в одном слоте.

0 голосов
/ 26 июля 2010

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

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

Это делается так:

update slots s
set slotValue=newValue
WHERE s.userID = <UserID> AND slotValue IS NULL AND NOT EXISTS 
(SELECT 1 FROM slots s2 WHERE s2.userid=s.userid AND s2.slotValue IS NULL AND s2.slotID<s.slotID)

Если вы добавляете поля slotNr в таблицу слотов (нумерацияслоты пользователя из 1..10) тогда запрос будет выглядеть так:

update slots s
set slotValue=newValue
WHERE s.userID = <UserID> AND slotValue IS NULL AND NOT EXISTS 
(SELECT 1 FROM slots s2 WHERE s2.userid=s.userid AND s2.slotValue IS NULL AND s2.slotNr<s.slotNr)

Когда вы выполняете запрос, база данных возвращает количество затронутых строк.Если все слоты используются, возвращаемое значение будет 0, иначе 1, если слот был обновлен.

Вы можете узнать, сколько свободных слотов есть, написав

select count(*) FROM slots 
WHERE slots.userID=<userID> AND slots.slotValue IS NULL

Хотя даже если это возвращает свободные слоты, нет никакой гарантии, что, когда вы действительно захотите изменить значение пустого слота, будут ли свободные слоты - другие операции, добавляющие значения слотов для этого пользователя, могут занять последний доступный слот.Поэтому лучше использовать переменную ROW_COUNT, чтобы определить, был ли изменен слот или нет.

0 голосов
/ 26 июля 2010

Я бы сказал, что может по-прежнему использовать строки.Просто добавьте столбец «SlotOrder» или что-то подобное.Затем ваш запрос выглядит примерно так (предупреждение: код psuedo - совсем не тестировался):

declare @Slot int
set @Slot = 1
if @Slot <= (Select Max(SlotOrder) from Inventory)
   select @Slot = (Select Max(SlotOrder) + 1 from Inventory)
if @Slot >= 10
   Insert Into Inventory(Item, SlotOrder)
   Values(@Item, @Slot)
Else -- Tell the user the inventory is full
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...