Ребята, помогите доктору, плиз!
Заранее прошу простить за наверное дилетантский вопрос, но так как я и есть пока дилетанат, то... :)
Имеется база данных по визитам пациентов[Report.mdb].
В данном случае у нас участвуют две связанные таблицы:
[PacientData] - данные пациента (номер пациента, имя, возраст, пол и т.д.)
[PacientVisit] - ВСЕ визиты ВСЕХ пациентов(номер пациента, дата визита, диагноз, назначения и пр.)
таблицы связаны через поле (PacNo)-номер пациента
На форме есть контрол Data1 и связанные с ним текстбоксы txtFields(7) - тут выводятся данные пациента,
Data1 связан с [PacientData],
также есть контрол Data2 и связанный с ним DBGrid1,
Data2 связан с Data1 через SQLзапрос (str1)
соответственно DBGrid1 показывает все визиты ТОЛЬКО ДАННОГО пациента
Это то, что мы имеем
Теперь, что нужно - собственно вопрос:
Я добавил на форму List1.
Нужно - привязать его к столбцу DateVisit в DBGrid1, чтобы в List1 отображались даты визитов ТОЛЬКО ДАННОГО пациента, а DBGrid1 показывал ТОЛЬКО ОДНУ строку соответствующую выбранному в List1 визиту.
Существующий кусок кода:
Option Explicit
Dim DBName As String
Dim tblName As String
Private Sub Form_Load()
DBName = "REPORT.MDB"
tblName = "PacientData"
With Data1
.DatabaseName = App.Path + DBName
.RecordsetType = vbRSTypeDynaset
.RecordSource = tblName
.Refresh
End With
End Sub
Public Sub Data1_Reposition()
Dim str1 As String
'В txtFields(0) отображается PacNo,
If txtFields(0).Text = Empty Then
txtFields(0).Text = "0"
End If
str1 = "SELECT * FROM PacientVisit WHERE PacNo=" & txtFields(0).Text
With Data2
.DatabaseName = App.Path + DBName
.RecordsetType = vbRSTypeDynaset
.RecordSource = str1
.Refresh
End With
DBGrid1.ReBind 'DBGrid1 привязан к Data2
End Sub
Самое главное - можно-ли решить задачу без ADO?
Т.е. иcпользуя уже имеющиеся Data1, Data2 и DBGrid1
Заранее спасибо
я бы не советовал использовать Data1 2... Лучше юзать если не ADO то DAO это одно и тоже токо без контролов.
от пример отображения в ListView определённой таблицы (DAO)
Public Sub WritetoListView(ListView As ListView, DBPath$, Password$, Table$) '+
'Отображает базу в ListView
Dim Db As Database, rs As Recordset
ListView.View = lvwReport
Set Db = OpenDatabase(DBPath$, False, False, "MS Access;pwd=" & Password$)
Set rs = Db.OpenRecordset("select * from [" & Table$ & "]"
For i = 0 To rs.Fields.Count - 1 'Создаём столюцы
ListView.ColumnHeaders.Add , , rs.Fields(i).Name
Next
If rs.EOF = False Then
'Заполняем значениями столбцы
While Not rs.EOF
Set lvItm = ListView.ListItems.Add(, , IIf(IsNull(rs(0)), "", rs(0)))
For i = 1 To rs.Fields.Count - 1
lvItm.SubItems(i) = IIf(IsNull(rs(i)), "", rs(i))
Next
sno = sno + 1
DoEvents
rs.MoveNext
Wend
End If
End Sub
Спасибо уважаемый HACKER, но...
1.Нужна связь не ListView с таблицей, а List с определенной колонкой DBGrid, согласитесь это несколько разные задачи.
2. Вы пишете /я бы не советовал использовать Data1 2... / , к сожалению, по определенным причинам (долго объяснять, да это никому и неинтересно) я не могу отказаться от использования Data1,2
3.Если Вы обратили внимание (я не случайно привел существующий код) - база уже открыта.
Можно ли встроиться сюда, или необходимо снова открывать базу через /Set Db=OpenDatabase/
Может я что-то непонимаю?
Ставишь свойство List - DataSource в Data2, a свойство List - DataField в нужное тебе поле даты,
Только после того как зальешь Data2 по SQL запросу. Т.е. DataSource можно прямо в редакторе свойств поставить, а DataField в коде после
str1 = "SELECT * FROM PacientVisit WHERE PacNo=" & txtFields(0).Text
With Data2
.DatabaseName = App.Path + DBName
.RecordsetType = vbRSTypeDynaset
.RecordSource = str1
.Refresh
End With
Потом у List есть событие Change (кажется) - выбор определенной строки. По нему строй запрос и заливай скажем Data3, к которому цепляй DBGrid.
уважаемый Walther, я конечно понимаю что я не кинул готовый кусок кода который будет полностью удовлетворять ваш вопрос, но...
While Not rs.EOF
Set lvItm = ListView.ListItems.Add(, , IIf(IsNull(rs(0)), "", rs(0)))
For i = 1 To rs.Fields.Count - 1
lvItm.SubItems(i) = IIf(IsNull(rs(i)), "", rs(i))
Next
sno = sno + 1
DoEvents
rs.MoveNext
Wend
представте что RS это и есть ваш Data1 или 2... тогда цикл While - Wend перебирает все строки в таблице, а цикл For - Next все колонки. В итоге если в For - Next "ловить" нужную Вам колонку и вместо ListView конечно использовать List то получится как раз заполнение List определённой колонкой.
-------------
Вобщем говоря на русском:
Эта хрень накиданная в том моём примере, отображает в ListView все колонки и строки, и доделывать и/или переделывать чтобы она отображала определённую колонку не в листвьюве а в обычном - несколько мин, даже если не открывать заново, а теми же Data 1 ...
Спасибо уважаемый АНДРЕЙ, Вы пишете Т.е. DataSource можно прямо в редакторе свойств поставить, а DataField в коде после,
но в этом как раз и вопрос.
То, что DataSource можно прямо в свойствах поставить, я знаю, а DataField сам VB не даст в свойствах поставить - будет ругаться /You need to fill in the RecordSource property of the Data control to get a list of field names/, потому, что свойства Data2 мы ставим в коде.
Весь фокус как этот блин List1.DataField поставить?
Код то какой?
Насколько я понимаю, там цикл должен быть?
Мне вот тут по мылу советовали такой код, через ADO, только не смогли сказать, как без ADO сделать.
'Список надо будет загружать вручную. Примерно так:
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
Set rs.ActiveConnection = <cnn>
rs.Open "iagnosValue"
List1.Clear
Do Until rs.EOF
List1.AddItem rs.Fields("Name".Value
List1.ItemData(List1.NewIndex) = rs.Fields("ID".Value
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
'Затем, при выборе элемента списка, обновлять грид:
Private Sub List1_Click()
Dim ID As Long
If List1.ListIndex >= 0 Then ID = List1.ItemData(List1.ListIndex)
If ID = 0 Then
Grid1.Filter = vbNullString
Else
Grid1.Filter = "[ID] = " & Trim$(Str$(ID))
End If
Grid1.Requery
End Sub
'Это примерный код, я его не проверял.
Но тут ADO и Grid, а у меня ведь Data и DBGrid, а у него нет такого фильтра как Grid1.Filter
Чего делать то?
Уважаемый HACKER пока готовил ответ АНДРЕЮ появилось Ваше сообщение. Спасибо. Попробую разобраться. Отвечу позже, что получилось.
Уважаемый доктор. Залить List1 нужными Вам датами не так уж сложно. Да, Вы были правы. Без цикла обойтись не получается.
После того как Вы залили Data2.
 ata2.Recordset.MoveFirst
Do
List1.AddItem Data2.Recordset!DateVisit
 ata2.Recordset.MoveNext
Loop Until Data2.Recordset.EOF
Теперь Вам понадобится еще один элемент Data3 с которым надо связать DBGrid1, а сам Data3 заливать так же запросом, но по List1_Click.
Здесь начинаются сложности с провайдером доступа к базе, сами увидите какие.
Запрос примерно такой
"select * from datviz where DateVizit=" & Left(List1.List(List1.ListIndex), Len(List1.List(List1.ListIndex)))
Спасибо уважаемый АНДРЕЙ, Ваш пример в первой части помог.
Список заполняется.
Правда пришлось еще добавить
List1.Clear
перед циклом, без этого список почему-то заполнялся данными несколько раз.
А вот во второй части Вы оказались правы - сложности.
Код такой (на основе Вашего)
Private Sub List1_Click()
Dim str2 As String
str2 = "select * from PACIENT_VISIT where DateVisit=" & Left(List1.List(List1.ListIndex), Len(List1.List(List1.ListIndex)))
With Data3
.DatabaseName = App.Path + "\DBASE\" + DBName
.RecordsetType = vbRSTypeDynaset
.RecordSource = str2
.Refresh
End With
End Sub
Когда кликаешь на произвольную позицию в списке (например дата визита была 14.06.2005) - пишет Run-time ошибку '3075':
Syntax error in number in query expression 'DateVisit=14.06.2005'
Вы не знаете, что это значит?
Что за синтаксическая ошибка в номере выражения запроса?
Ругается зараза на
.Refresh
, т.е. не дает обновить.
Data3 заливается копией кода заливки Data2(он парой строк выше), только естественно запрос другой, вот и вся разница - так там на
Дело все в том, что DAO как то по другому работает с датами нежели ADO. Там этот запрос проходит на ура, если саму дату ограничить апострофами. Зайдите сюда
http://www.vbrussian.com/conf/default.asp
там мы давно это обсуждаем в теме SQL.
А про Clear я просто забыл, надо конечно очищать список перед новым заполнением, ведь метод AddItem просто добавляет новый элемент в конец списка.
Спасибо уважаемый АНДРЕЙ, после внимательного изучения по Вашему совету темы SQL, код принял следующий вид
Private Sub List1_Click()
Dim str2 As String
Dim L As String
L = CLng(DateValue(List1.List(List1.ListIndex)))
str2 = "select * from PACIENT_VISIT where DateVisit=" & Left(L, Len(L))
With Data3
.DatabaseName = App.Path + "\DBASE\" + DBName
.RecordsetType = vbRSTypeDynaset
.RecordSource = str2
.Refresh
End With
DBGrid1.ReBind
End Sub
Все вроде-бы заработало, в Grid1 стали отображаться записи, правда связь получилась такая - в List1 отображаются все визиты ТОЛЬКО данного пациента (что и требовалось), а в Grid1 отображается не уникальная строка соответсвующая ТОЛЬКО этому визиту пациенту, а все визиты разных пациентов, которые были в день выбранный в List1. Но это я думаю вылечить, просто нужно наверное усовершенствовать запрос.
Тут получилась другая странная вешь - когда пытаешься добавить новый визит, в саму базу данных новые данные вносятся, в List1 тоже появляется новая стока, а в Grid1 почему новая строка не отображалась (вернее отображается пустая).
Мучился целый день - и так и эдак, в конце концов обратил внимание, что в момент клика в List1, грид прежде чем отобразиться, как то странно мигает один раз. Пригляделся - в поле DateVisit мелькает не дата, а число.
Попробовал прописать явно формат поля DateVisit кодом
Format(имя переменной, "dd.mm.yy"
- все заработало.
Хотя в свойствах таблицы в базе данных тип поля уже был определен, как "Краткий формат даты".
Странно это, господа
глюки, глюки...
Спасибо еще раз!
Неужели наконец сдвинусь с места.
а в Grid1 отображается не уникальная строка соответсвующая ТОЛЬКО этому визиту пациенту, а все визиты разных пациентов, которые были в день выбранный в List1. Но это я думаю вылечить, просто нужно наверное усовершенствовать запрос.
Вы абсолютно правы. В запрос надо добавить второе условие (через and) c ID пациента.Т.е примерно так
str2 = "select * from PACIENT_VISIT where (DateVisit=" & Left(L, Len(L)) & " and (PacNo=" & txtFields(0).Text & ""
Насчет глюков Вы не правы. VB совсем не обязательно знать, что Вы там в Access установили.