PDA

View Full Version : MaxDate And Min Date َ و حذف گروهی



پرستو پارسایی
چهارشنبه 20 آذر 1398, 13:39 عصر
سلام
1 -نحوه بدست آوردن کوچکترین تاریخ شمسی و بزرگترین تاریخ شمسی لود شده در دیتا گرید رو میخوام بدونم . فرمت ( 1398/06/22)
2 -چه جوری میتونم تاریخ های که تو دیتا گرید فیلتر کردم رو یکجا حذف کنم. مثلا تعداد زیادی رکورد دارم و وقتی فیلتر میکنم 15 رکود نمایش داده میشه . این 15 رکورد رو چه جوری یکجا از دیتابسیم (SQL) حذف کنم
ممنون میشم در صورت اطلاع پاسخ دهید

پرستو پارسایی
پنج شنبه 21 آذر 1398, 12:10 عصر
سلام وجدد به دوستان
با این کد minDate و maxDate رو از دیتا گرید لود کردم
ولی بخش دوم سوالم رو درمورد حذف چند رکورد همزمان رو موفق نبودم ممنون میشم دوستان اگر اطلاع دارید پاسخ دهید سپاس


Private Structure cell
Dim rowIndex As Integer
Dim columnIndex As Integer
End Structure

'''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''Event Btn''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''


Dim cells = From r As DataGridViewRow In DataGridView1.Rows.Cast(Of DataGridViewRow)() _
Where Not r.IsNewRow _
Select CStr(r.Cells(1).Value)


Dim min As String = cells.Min
Dim minAddress As New cell With {.columnIndex = 0, .rowIndex = Array.IndexOf(cells.ToArray, min)}
Dim max As String = cells.Max
Dim maxAddress As New cell With {.columnIndex = 0, .rowIndex = Array.IndexOf(cells.ToArray, max)}
TextBox1.Text = min
TextBox2.Text = max

the king
پنج شنبه 21 آذر 1398, 18:45 عصر
سلام
1 -نحوه بدست آوردن کوچکترین تاریخ شمسی و بزرگترین تاریخ شمسی لود شده در دیتا گرید رو میخوام بدونم . فرمت ( 1398/06/22)


With DataGridView1.Rows
If .Count > 0 Then
Dim minDate As String = .Item(0).Cells.Item("Date").Value
Dim maxDate As String = minDate
For i = 1 To .Count - 1
Dim d As String = .Item(i).Cells.Item("Date").Value
If d Is Nothing OrElse d.Length <> 10 Then Continue For
If minDate > d Then minDate = d
If maxDate < d Then maxDate = d
Next
TextBox1.Text = minDate
TextBox2.Text = maxDate
End If
End With




2 -چه جوری میتونم تاریخ های که تو دیتا گرید فیلتر کردم رو یکجا حذف کنم. مثلا تعداد زیادی رکورد دارم و وقتی فیلتر میکنم 15 رکود نمایش داده میشه . این 15 رکورد رو چه جوری یکجا از دیتابسیم (SQL) حذف کنم
ممنون میشم در صورت اطلاع پاسخ دهید
اگر بخواهید یک رکورد رو بر اساس سطر در DataGridView حذف کنید بهتره که کلید اون رکورد رو هم در ستون ها داشته باشید. حتی میتونه اون ستون مخفی از دید کاربر باشه ولی به هر حال برای حذف کردن دقیق به Id یا کلید رکورد نیاز هست.

DataGridView1.Columns.Item("Id").Visible = False



With DataGridView1
If .Rows.Count > 0 Then
Using connection As New SqlConnection(connectionString)
connection.Open()
Using command As New SqlCommand("DELETE FROM [YourTable] WHERE [Id] IN (", connection)
Dim pList As New List(Of String)
For i = 0 To .Rows.Count - 1
If .Rows.Item(i).Cells.Item("Id").Value Is Nothing Then Continue For
pList.Add("@p" + i.ToString())
command.Parameters.AddWithValue("@p" + i.ToString(), .Rows.Item(i).Cells.Item("Id").Value)
Next
command.CommandText += String.Join(",", pList.ToArray()) + ");"
command.ExecuteNonQuery()
End Using
End Using
End If
.DataSource = Nothing
.Rows.Clear()
End With

پرستو پارسایی
پنج شنبه 21 آذر 1398, 21:20 عصر
سلام ممنونم از پاسختان باز هم یک پاسخ عالی (سپاس)

mazoolagh
شنبه 23 آذر 1398, 09:47 صبح
چند سئوال برای من پیش آمده که با اجازه یکی یکی مطرح میکنم:

1- کدی که استارتر تاپیک در پست 2 گذاشته بودن درست بود (هر چند که ساده تر میشه نوشت)، چرا باید حلقه بگذاریم برای پیدا کردن min / max ؟
dim dates=from row as datagridviewrow in DataGridView1.rows where row.cells("date").value isnot nothing select row.cells("date").value
if dates.count > 0 then
TextBox1.Text=dates.min()
TextBox2.Text=dates.max()
end if

mazoolagh
شنبه 23 آذر 1398, 09:53 صبح
2- برای پیدا کردن min/max میشه مستقیم از compute برای datatable هم استفاده کرد:

dim dt as datatable=DataGridView1.datasource.defaultview.tot able
TextBox1.Text=dt.compute("min(date)","")
TextBox2.Text=dt.compute("max(date)","")


و باز هم نیازی به حلقه نیست

mazoolagh
شنبه 23 آذر 1398, 10:12 صبح
3- برای ساختن لیست ID ها و گذاشتن اون در commandtext هم باز نیازی به حلقه نیست:

dim ids=from row as datagridviewrow in DataGridView1.rows where row.cells("id").value isnot nothing select row.cells("id").value
With DataGridView1
Using connection As New SqlConnection(connectionString)
connection.Open()
Using command As New SqlCommand
command.CommandText = "DELETE FROM [YourTable] WHERE [Id] IN (@ids)".replace("@ids",join(ids.toarray,","))
command.ExecuteNonQuery()
End Using
End Using
.DataSource = Nothing
.Rows.Clear()
End With

پرستو پارسایی
شنبه 23 آذر 1398, 12:18 عصر
ممنونم از توجه شما کد شما خیلی کمک کرد سپاس

the king
شنبه 23 آذر 1398, 18:52 عصر
چند سئوال برای من پیش آمده که با اجازه یکی یکی مطرح میکنم:

1- کدی که استارتر تاپیک در پست 2 گذاشته بودن درست بود (هر چند که ساده تر میشه نوشت)، چرا باید حلقه بگذاریم برای پیدا کردن min / max ؟
dim dates=from row as datagridviewrow in DataGridView1.rows where row.cells("date").value isnot nothing select row.cells("date").value
if dates.count > 0 then
TextBox1.Text=dates.min()
TextBox2.Text=dates.max()
end if



سوال خیلی خوبی است. حلقه یا Linq یا هر روش دیگری که برای حل مساله بکار می بریم نیاز ما نیستند، نیاز ما حل مساله است که برای حل کردنش هم گزینه های مختلفی داریم.
اون چیزی که در انتخاب بین این گزینه ها کمک می کنه مقایسه روش ها است، پیچیدگی زمانی شون، زمان لازم برای نوشتن شون، زمان اجراشون، خوانایی کد شون و ...
متاسفانه همیشه نمیشه همه پارامتر ها رو در حد مطلوب نگهداشت، مثلا کدی که شما نوشتید از نظر تعداد سطر کد خیلی خوبه، اما زمان لازم برای اجراش به مراتب کند تر از اون کد طولانی تری است که من با حلقه for نوشتم :


Private _dg As New DataGridView
Private _lst As New ListBox

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim source As New DataTable
_lst.Parent = Me
_lst.Dock = DockStyle.Fill
source.Columns.Add("Date")
Dim rnd As New Random
For i = 0 To 100000
Dim row As DataRow = source.NewRow
row("Date") = $"{rnd.Next(1300, 1400)}/{rnd.Next(1, 12)}/{rnd.Next(1, 30)}"
source.Rows.Add(row)
Next
_dg.DataSource = source
_dg.Parent = Me
_dg.Dock = DockStyle.Right
End Sub

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim elapsed As Long
Button1.Enabled = False
_lst.Items.Add("please wait...")
Application.DoEvents()


_lst.Items.Add("Method1...")
Dim sw As New Stopwatch
sw.Start()
Dim dates = From row As DataGridViewRow In _dg.Rows Where row.Cells("date").Value IsNot Nothing Select row.Cells("date").Value
If dates.Count > 0 Then
TextBox1.Text = dates.Min()
TextBox2.Text = dates.Max()
End If


sw.Stop()
elapsed = sw.ElapsedTicks
_lst.Items.Add("Elapsed (ticks): " & sw.ElapsedTicks)
sw.Reset()
_lst.Items.Add("Method2...")
Application.DoEvents()
sw.Start()


With _dg.Rows
If .Count > 0 Then
Dim minDate As String = .Item(0).Cells.Item("Date").Value
Dim maxDate As String = minDate
For i = 1 To .Count - 1
Dim d As String = .Item(i).Cells.Item("Date").Value
If d Is Nothing OrElse d.Length <> 10 Then Continue For
If minDate > d Then minDate = d
If maxDate < d Then maxDate = d
Next
TextBox1.Text = minDate
TextBox2.Text = maxDate
End If
End With


sw.Stop()
_lst.Items.Add("Elapsed (ticks): " & sw.ElapsedTicks)
_lst.Items.Add($"Method 1 is {((elapsed - sw.ElapsedTicks) / sw.ElapsedTicks):0.0} times slower.")
Button1.Enabled = True
End Sub

من اگه از حلقه for استفاده کردم نه به این خاطر بود که Linq رو نمیشناسم. نه علاقه خاصی به for دارم و نه Linq
دقیقا به این خاطر بود که Linq رو میشناختم، میدونستم که استفاده ازش با وجود کاهش حجم کد نویسی چقدر کارایی در اجرا رو پایین میاره.
از روی ظاهر کدها نمیشه قضاوت کرد، مثل تفاوت ظاهری کد الگوریتم های مرتب سازی حبابی و مرتب سازی سریع

the king
شنبه 23 آذر 1398, 18:57 عصر
2- برای پیدا کردن min/max میشه مستقیم از compute برای datatable هم استفاده کرد:

dim dt as datatable=DataGridView1.datasource.defaultview.tot able
TextBox1.Text=dt.compute("min(date)","")
TextBox2.Text=dt.compute("max(date)","")


و باز هم نیازی به حلقه نیست


حلقه نیاز ما نیست، همونطور که کند شدن کد هم نیاز ما نیست. ما کدی رو انتخاب میکنیم که کارایی بهتری ایجاد کنه، مگر اینکه بخواهیم به دلیل خاصی ازش اجتناب کنیم.
چه نیازی داریم که کدی بنویسیم که چند برابر کند بشه؟ صرفا برای اینکه حلقه نداشته باشه؟ حلقه داشتن و نداشتن به خودی خود هیچ ارزش یا عیبی محسوب نمیشه.

Private _dg As New DataGridView
Private _lst As New ListBox

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim elapsed As Long
Button2.Enabled = False
_lst.Items.Add("please wait...")
Application.DoEvents()


_lst.Items.Add("Method1...")
Dim sw As New Stopwatch
sw.Start()
Dim dt As DataTable = _dg.DataSource.DefaultView.ToTable
TextBox1.Text = dt.Compute("min(date)", "")
TextBox2.Text = dt.Compute("max(date)", "")
sw.Stop()
elapsed = sw.ElapsedTicks
_lst.Items.Add("Elapsed (ticks): " & sw.ElapsedTicks)
sw.Reset()
_lst.Items.Add("Method2...")
Application.DoEvents()
sw.Start()


With _dg.Rows
If .Count > 0 Then
Dim minDate As String = .Item(0).Cells.Item("Date").Value
Dim maxDate As String = minDate
For i = 1 To .Count - 1
Dim d As String = .Item(i).Cells.Item("Date").Value
If d Is Nothing OrElse d.Length <> 10 Then Continue For
If minDate > d Then minDate = d
If maxDate < d Then maxDate = d
Next
TextBox1.Text = minDate
TextBox2.Text = maxDate
End If
End With


sw.Stop()
_lst.Items.Add("Elapsed (ticks): " & sw.ElapsedTicks)
_lst.Items.Add($"Method 1 is {((elapsed - sw.ElapsedTicks) / sw.ElapsedTicks):0.0} times slower.")
Button2.Enabled = True
End Sub

the king
شنبه 23 آذر 1398, 19:03 عصر
3- برای ساختن لیست ID ها و گذاشتن اون در commandtext هم باز نیازی به حلقه نیست:

dim ids=from row as datagridviewrow in DataGridView1.rows where row.cells("id").value isnot nothing select row.cells("id").value
With DataGridView1
Using connection As New SqlConnection(connectionString)
connection.Open()
Using command As New SqlCommand
command.CommandText = "DELETE FROM [YourTable] WHERE [Id] IN (@ids)".replace("@ids",join(ids.toarray,","))
command.ExecuteNonQuery()
End Using
End Using
.DataSource = Nothing
.Rows.Clear()
End With


مثالی که زدید ظاهر خوبی داره. اما یک ایراد بزرگ هم داره. مستعد SQL Injection ئه.
اگر کاربر ستون id رو ببینه و بتونه داحلش مقدار دلخواهش رو وارد کنه میتونه کد SQL ای رو اجرا کنه که مطلوب نیست. انتخاب Parameters بخاطر همینه که از SQL Injection جلوگیری بشه.

پرستو پارسایی
یک شنبه 24 آذر 1398, 11:28 صبح
ممنونم از پاسختان بسیار آموزنده بود . من فکر میکردم کد نویسی بخش بزرگیش مثل امضاء برنامه نویسش هست چون به چندین روش انجام میشه ولی با این توضیحات نظرم تغییر کرد .
الان متوجه شدم برای نوشتن یک کد فقط نیاید به انجام دادن Event اون قطعه کد فکر کرد ، بلکه میبایست سایر پارامترها رو هم برای بهبودکیفیت در نظر گرفت.
به هر حال من فکر میکنم هدف مدیران محترم سایت (بخش آموزش) هست و دوستان همه تلاش میکنند تا بهم کمک کنن .
من مجددا از پاسخگویی دوستان بخاطر به اشتراک گذاشتن اطلاعات با ارزششان کمال تشکر را دارم .

mazoolagh
دوشنبه 25 آذر 1398, 13:22 عصر
@the king
قبل از هر چیز باید تشکر کنم از این که با حوصله و دقیق پاسخ میدین،
و خوشحالم که متوجه هستین که هدف از این پرسشها هم صرفا یادگیری و دونستن چراها هست.
و همچنین تشکر از استارتر تاپیک که بانی خیر شدن.

نمیدونم وقت و حوصله دارین یا نه، ولی هنوز چند مورد هست (هم در زمینه همین ها که مطرح شد و هم نکات دیگه) که اگر اجازه بدین در همین تاپیک بپرسم.

==========
خارج از موضوع : به اختلاف نظر اهل فن درباره روش های سورت اشاره کردین و همچنین پرفورمنس برنامه؛ شاید جالب باشه بدونین که اون قدیما که دیتا روی کارت های موسوم به هالریت پانچ میشد وقت سیستم بطور کلی و وقت پردازشگر بطور خاص اونقدر مهم بود که دیتا رو قبل از پردازش اول با یک دستگاه مکانیکی سورت میکردن!
تقریبا تمام سایت های کامپیوتری حداقل یک دستگاه IBM 084 داشتن که از نظر فنی و پیچیدگی شاهکاری بود برای خودش و راحت 30-40 کارت (رکورد) رو میتونست در ثانیه سورت کنه.

the king
دوشنبه 25 آذر 1398, 15:14 عصر
@the king
قبل از هر چیز باید تشکر کنم از این که با حوصله و دقیق پاسخ میدین،
و خوشحالم که متوجه هستین که هدف از این پرسشها هم صرفا یادگیری و دونستن چراها هست.
و همچنین تشکر از استارتر تاپیک که بانی خیر شدن.

نمیدونم وقت و حوصله دارین یا نه، ولی هنوز چند مورد هست (هم در زمینه همین ها که مطرح شد و هم نکات دیگه) که اگر اجازه بدین در همین تاپیک بپرسم.

من از شما ممنونم که در مباحث شرکت می کنید.
معلوماتم زیاد نیست ولی حوصله ام چرا. اگه مباحث به کسی کمکی بکنه خوشحال میشم در اونها مشارکت داشته باشم.



خارج از موضوع : به اختلاف نظر اهل فن درباره روش های سورت اشاره کردین و همچنین پرفورمنس برنامه؛ شاید جالب باشه بدونین که اون قدیما که دیتا روی کارت های موسوم به هالریت پانچ میشد وقت سیستم بطور کلی و وقت پردازشگر بطور خاص اونقدر مهم بود که دیتا رو قبل از پردازش اول با یک دستگاه مکانیکی سورت میکردن!
تقریبا تمام سایت های کامپیوتری حداقل یک دستگاه IBM 084 داشتن که از نظر فنی و پیچیدگی شاهکاری بود برای خودش و راحت 30-40 کارت (رکورد) رو میتونست در ثانیه سورت کنه.

کارت های پانج شده رو یادم میاد، خواهرم در دانشگاه ازشون استفاده میکرد. دانشجو ها باید کارت ها رو پانچ شده و شماره گذاری شده تحویل سایت میدادن و فردا پسفردا میومدن نتیجه رو تحویل بگیرن که ببینن آیا اشتباهی داشتن یا نه.
حالا مصبت کار با اون IBM 084 به کنار، لااقل ابعادش منطقی بود. پدرم تعریف کرده بود که وقتی برای سازمان آب منطقه ای کامپیوتر آوردن یک هیولایی بود اندازه یک اتاق بزرگ که خودش باید در یک سالن بزرگ با شرایط دما و رطوبت خاصی جای میگرفت.