PDA

View Full Version : سوال: دستور select برای 2 رکورد خاص



mojniknam
شنبه 23 آذر 1387, 21:44 عصر
سلام
یه سوال عجیب...
میخوام با یه دستور select مقدار رکوردهای محدوده n1 و n2 از جدول رو بر گردونم!
به عنوان مثال جدول من 50 تا رکورد داره و من میخوام با یه دستور select محدوده رکورد های 10 تا 15 را بدست بیارم.
امیدوارم که بشه

alishirazi
شنبه 23 آذر 1387, 23:08 عصر
اگه منظورت از رکوردهای 10 تا 15 ID 10 تا 15 هست ساده هست اکه درست فهمیده باشم،

Select * From yourTable where ID > 10 And Id < 15
اگه منظورت چیز دیگه هست بیشیتر بتوضیح

AminSobati
شنبه 23 آذر 1387, 23:21 عصر
سلام دوست عزیزم،
در SQL Server 2005 میتونین روی جدول Rank بزارین (شماره از 1 تا N) و بعد روی فیلد Rank شرط اعمال کنید

alishirazi
شنبه 23 آذر 1387, 23:56 عصر
ببین اگه منظورت سطرهای 10 تا 15 بیاره با یه query مثله این میشه :

Select * From [User] where Id in (select top(15) Id From [user]) and Id not in ( select top(5) Id from [user])
این از table user من سطرهای مثلا 5 تا 15 رو میاره

mojniknam
یک شنبه 24 آذر 1387, 00:03 صبح
سلام دوست عزیزم،
در SQL Server 2005 میتونین روی جدول Rank بزارین (شماره از 1 تا N) و بعد روی فیلد Rank شرط اعمال کنید
لطف میکنید دستور select این شیوه رو توی 2005 بگین؟
ببخشید چون من برنام نویس asp.net هستم زیاد از دستورات sql سر در نمیارم.

Sal_64
سه شنبه 03 دی 1387, 21:38 عصر
سلام


لطف میکنید دستور select این شیوه رو توی 2005 بگین؟

با تشکر

تولائی
سه شنبه 03 دی 1387, 22:40 عصر
فرض کنید جدول tbl@ را با سه ستون داریم و مقادیر را را بصورت زیر وارد کرده‌ایم. می‌خواهیم رکوردهای 10 تا 15 از این جدول را مرتب شده بر حسب نام بخوانیم. کد زیر مناسب است.


declare @tbl as table (Id int not null , code int not null
, name varchar(50) not null, PRIMARY KEY (Id))
insert into @tbl values(1,2,'a')
insert into @tbl values(2,3,'b')
insert into @tbl values(3,4,'c')
insert into @tbl values(4,5,'d')
insert into @tbl values(5,6,'e')
insert into @tbl values(6,7,'f')
insert into @tbl values(7,8,'g')
insert into @tbl values(8,9,'h')
insert into @tbl values(9,10,'i')
insert into @tbl values(10,11,'j')
insert into @tbl values(11,12,'k')
insert into @tbl values(12,13,'l')
insert into @tbl values(13,14,'z')
insert into @tbl values(14,15,'y')
insert into @tbl values(15,16,'x')
insert into @tbl values(16,17,'t')
insert into @tbl values(17,18,'u')
insert into @tbl values(18,19,'w')
insert into @tbl values(19,20,'r')
select top 5 Id, code, name from
(select ROW_NUMBER() over(order by name) rownumber, * from @tbl) tblOrderbyName
where rownumber > 10

من windowsم 2003 است. نمی‌دونم چرا دکمه‌های اون بالا فعال نیست. به هر حال همه‌رو تو یک خط می‌نویسه. اگه وقت داشتم فردا درستش می‌کنم.

AminSobati
سه شنبه 03 دی 1387, 23:30 عصر
لطف میکنید دستور select این شیوه رو توی 2005 بگین؟
ببخشید چون من برنام نویس asp.net هستم زیاد از دستورات sql سر در نمیارم.



use northwind
go
select * from
(select row_number() over(order by orderid) as MyRank,* from orders) tmp
where MyRank between 10 and 15

Sal_64
جمعه 06 دی 1387, 10:20 صبح
سلام
جناب ثباتی
اگه اشتباه نکنم کد شما بر طبق فیلد orderid سورت کرده و سپس عمل سلکت انجام میشه

آیا راهی وجود داره که بدون وابستگی به فیلد خاصی عمل سلکت انجام شه

واضحتر یعنی اینکه بر طبق موقعیت رکورد در جدول این انتخاب انجام شه و رکوردها به همون ترتیب که ذخیره شدن در سلکت بر گردونده شن


با تشکر

mojniknam
جمعه 06 دی 1387, 13:07 عصر
use northwind
go
select * from
(select row_number() over(order by orderid) as MyRank,* from orders) tmp
where MyRank between 10 and 15


اگر میشه یه توضیحی روی این کد بدین

AminSobati
جمعه 06 دی 1387, 14:36 عصر
سلام
جناب ثباتی
اگه اشتباه نکنم کد شما بر طبق فیلد orderid سورت کرده و سپس عمل سلکت انجام میشه

آیا راهی وجود داره که بدون وابستگی به فیلد خاصی عمل سلکت انجام شه

واضحتر یعنی اینکه بر طبق موقعیت رکورد در جدول این انتخاب انجام شه و رکوردها به همون ترتیب که ذخیره شدن در سلکت بر گردونده شن


با تشکر

همیشه وقتی شماره ردیف بوجود میاریم، باید ترتیبی وجود داشته باشه تا این شماره روی اون ترتیب ارائه بشه. از دید SQL Server، چون با نظریه مجموعه ها (Set Theory) کار میکنه، ترتیب ورود به جدول بی معنیه. مگر اینکه فرضا یک فیلد افزایشی وجود داشته باشه و نتیجه رو بر حسب اون Order BY کنیم. اگر Order By در Query قید نشه، SQL Server مجاز خواهد بود طبق هر ترتیبی رکوردها رو نمایش بده.

AminSobati
جمعه 06 دی 1387, 14:37 عصر
اگر میشه یه توضیحی روی این کد بدین

تابع Row_Number میتونه شما ردیف تولید کنه. در قسمت OVER بعضی تنظیمات این تابع قید میشن. از اونجایی که فیلد Rank یا همون شماره ردیف در جدول (قسمت FROM) وجود نداره لذا نمیتونیم در WHERE بهش اشاره کنیم. پس اون رو در یک Subquery قرار میدیم تا مشکل حل بشه

تولائی
جمعه 06 دی 1387, 16:13 عصر
سلام
جناب ثباتی
اگه اشتباه نکنم کد شما بر طبق فیلد orderid سورت کرده و سپس عمل سلکت انجام میشه

آیا راهی وجود داره که بدون وابستگی به فیلد خاصی عمل سلکت انجام شه

واضحتر یعنی اینکه بر طبق موقعیت رکورد در جدول این انتخاب انجام شه و رکوردها به همون ترتیب که ذخیره شدن در سلکت بر گردونده شن


با تشکر
سلام
فرمایشات جناب AminSobati بسیار سنجیده و متین است ولی شاید منظورتان این است فرض کنید داریم


select * from orders

حال می‌خواهیم روی همین مجموعه داده سطرهای 10 تا 15 را بخوانیم. بدون هیچ‌گونه order byیی. حال باید چه کرد.
این کار را می‌توان با یک حقه کوچک انجامید.
به کد زیر توجه کنید:


use northwind
go
select * from
(select row_number() over(order by tmp) as MyRank,* from
(select 1 tmp,* from orders) tmp
) tmp
where MyRank between 10 and 15

این کوئری همان کاری که گفته شد را انجام خواهد داد.

AminSobati
جمعه 06 دی 1387, 17:32 عصر
دوست عزیزم با توجه به اینکه با قرار دادن عدد 1، عمل Order By رو بی اثر کردین، باز هم طبق نظریه مجموعه ها SQL Server مجاز خواهد بود هر 5 رکوردی رو بعنوان محدوده 10 تا 15 برگردونه. وقتی ترتیبی حاکم نیست، منطقا هر دسته 5 تایی از رکوردها میتونن پاسخ WHERE شما باشند!

تولائی
جمعه 06 دی 1387, 21:10 عصر
جناب AminSobati فرمایش شما در صورتی درست است که بین اجرا این دو کد که ذکر خواهد شد روی یک پایگاه داده ثابت از لحاظ ترتیب سطور تفاوت وجود داشته باشد.



select * from orders



select * from
(select * from orders) tmp

اگر این طور است بسیار از یک مثال یا یک مستند (document) استقبال می‌کنم. به نظرم می‌رسد که در کوئری دوم قرار است که تمام داده‌هایی را که در ساب‌کوئری آمده به‌تمامی به همان ترتیب نشان دهد. مگر آن که بگویید که اگر کوئری اول چند بار اجرا کنیم نتیجه را با چند ترتیب متفاوت می‌توان مشاهده کرد. من یک چنین چیزی را ندیده‌ام. گو این‌که با شما موافقم که Sql Server هیچ ضمانتی در قبال این مسئله نمی‌کند. که من چنین چیزی را تا بحال ندیده‌ام. مسئله دیگر این است که من چگونه و با چه تغییری می‌توانم تضمین کنم که در گزارش بالا یکسان شوند.

Sal_64
جمعه 06 دی 1387, 21:50 عصر
سلام

جناب تولائی

تشکر از کد شما هم استفاده کردم
به جز اضافه کردن ستون tmp با مقدار یک تفاوت دیگه ای با کد جناب ثباتی ایجاد نکرد
جواب برگشت داده شده به صورت صعودی مرتب شده بود



ترتیب ورود به جدول بی معنیهجناب ثباتی گاهی اوقات کاربر ارشد(مسئول برنامه بدون دسترسی مستقیم به SQL) احتیاج داره به آخرین رکورد یا رکوردها دسترسی داشته باشد حال تیبلی بدون هیچگونه فیلد مخصوص برای این کار مسئله ساز میشه

برای این منظور راهکاری وجود داره؟


با تشکر

تولائی
جمعه 06 دی 1387, 23:01 عصر
تشکر از کد شما هم استفاده کردم
به جز اضافه کردن ستون tmp با مقدار یک تفاوت دیگه ای با کد جناب ثباتی ایجاد نکرد
جواب برگشت داده شده به صورت صعودی مرتب شده بود


یک تفاوت عمده وجود داشت و اون این بود که هیچ قیدی روی هیچ فیلدی از جدول نبود.


جناب ثباتی گاهی اوقات کاربر ارشد(مسئول برنامه بدون دسترسی مستقیم به SQL) احتیاج داره به آخرین رکورد یا رکوردها دسترسی داشته باشد حال تیبلی بدون هیچگونه فیلد مخصوص برای این کار مسئله ساز میشه

برای این منظور راهکاری وجود داره؟


من اگر بخواهم بجای آقای ثباتی جواب دهم استفاده از یک شناسه‌ی (Id) خودافزا(!!)(Auto increment) رو پیشنهاد می‌کنم. در این صورت بزرگ‌ترین مقدار این شناسه متناظر آخرین رکود آن جدول است.

AminSobati
شنبه 07 دی 1387, 00:02 صبح
جناب AminSobati فرمایش شما در صورتی درست است که بین اجرا این دو کد که ذکر خواهد شد روی یک پایگاه داده ثابت از لحاظ ترتیب سطور تفاوت وجود داشته باشد.



select * from orders



select * from
(select * from orders) tmp

اگر این طور است بسیار از یک مثال یا یک مستند (document) استقبال می‌کنم. به نظرم می‌رسد که در کوئری دوم قرار است که تمام داده‌هایی را که در ساب‌کوئری آمده به‌تمامی به همان ترتیب نشان دهد. مگر آن که بگویید که اگر کوئری اول چند بار اجرا کنیم نتیجه را با چند ترتیب متفاوت می‌توان مشاهده کرد. من یک چنین چیزی را ندیده‌ام. گو این‌که با شما موافقم که Sql Server هیچ ضمانتی در قبال این مسئله نمی‌کند. که من چنین چیزی را تا بحال ندیده‌ام. مسئله دیگر این است که من چگونه و با چه تغییری می‌توانم تضمین کنم که در گزارش بالا یکسان شوند.

منطق زبان SQL یک بحثه و شیوه عمل SQL Server بحث دیگه. وقتی شما select * from orders انجام میدین SQL Server یک ایندکس رو یا شاید خود جدول رو (Heap) انتخاب میکنه تا اطلاعات به شما برگرده. اگر در هر بار اجرا ترتیبهای متفاوتی رویت کنید، چیزی خلاف منطق زبان SQL یا نظریه مجموعه ها اتفاق نیافتاده. اما تصور نکنید در هر با اجرا واقعا ترتیب عوض بشه چون شرایط ثابت بوده. اگر شرایط ایندکسها عوض بشه ممکنه نتیجه متفاوتی از نظر ترتیب بدست بیاد. این مثال رو ببینید، ابتدا Query انجام میدیم:



use northwind
go

select orderdate,customerid,orderid from orders
go


قبل از انجام Query بعدی، کاربر دیگه ای ایندکسی میسازه و بعد دوباره به این روش Query میگیریم:



create index ix1 on orders(customerid,orderid,orderdate)
go

select * from
(select orderdate,customerid,orderid from orders) tmp


نتیجه Query اول و دوم متفاوته. تنها چیزی که یکسان بودن نتیجه این دو Query رو تضمین میکنه، استفاده از Order By هست. دقت کنید که در حالت Subquery، بیرونی ترین Query باید Order By انجام بده.

AminSobati
شنبه 07 دی 1387, 00:06 صبح
سلام

جناب تولائی

تشکر از کد شما هم استفاده کردم
به جز اضافه کردن ستون tmp با مقدار یک تفاوت دیگه ای با کد جناب ثباتی ایجاد نکرد
جواب برگشت داده شده به صورت صعودی مرتب شده بود


جناب ثباتی گاهی اوقات کاربر ارشد(مسئول برنامه بدون دسترسی مستقیم به SQL) احتیاج داره به آخرین رکورد یا رکوردها دسترسی داشته باشد حال تیبلی بدون هیچگونه فیلد مخصوص برای این کار مسئله ساز میشه

برای این منظور راهکاری وجود داره؟


با تشکر

اگر واقعا هیچ فیلدی که ترتیب رو مشخص کنه وجود نداره، باید SQL Server رو مجبور کنید تا از خود جدول برای Scan استفاده کنه و سراغ سایر ایندکسها نره:



select * from mytable with(index(0))


با فرض به اینکه همیشه آخرین رکورد در ته جدول قرار گرفته، الان آخرین رکورد همونی هست که نیاز دارید

Sal_64
شنبه 07 دی 1387, 00:16 صبح
سلام
جناب ثباتی تشکر


اگر واقعا هیچ فیلدی که ترتیب رو مشخص کنه وجود نداره، باید SQL Server رو مجبور کنید تا از خود جدول برای Scan استفاده کنه و سراغ سایر ایندکسها نره:از اون کد استفاده کردم احتمالا درست این کار رو انجام ندادم یا ...
چون تمام رکوردها رو برگردوند
اون index کارش چیه؟

حالا اگر به 10 یا 20 یا x تعداد رکورد آخر احتیاج باشه چی ؟


با تشکر

تولائی
شنبه 07 دی 1387, 09:59 صبح
اگر در هر بار اجرا ترتیبهای متفاوتی رویت کنید، چیزی خلاف منطق زبان SQL یا نظریه مجموعه ها اتفاق نیافتاده.

با این قسمت از بحثتان کاملا موافقم.



اما تصور نکنید در هر بار اجرا واقعا ترتیب عوض بشه چون شرایط ثابت بوده. اگر شرایط ایندکسها عوض بشه ممکنه نتیجه متفاوتی از نظر ترتیب بدست بیاد.

اما در این قسمت از بحثتان اشاره به این مطلب نمودید که «اگر شرایط ایندکسها عوض بشه ممکنه نتیجه متفاوتی از نظر ترتیب بدست بیاد.». مسئله من این‌ه که اگر من داشته باشم


use northwind
go

select orderdate,customerid,orderid from orders
go

و این کوئری رو در query analyzer باز کنم و روی آن دو بار F5 بزنم بدون این‌که در پایگاه داده
northwind چه در ساختار چه در داده کوچک‌ترین دخل و تصرفی کنم می‌توانم توقع داشته باشم که نتیجه یکسان ببینم یا نه.



این مثال رو ببینید، ابتدا Query انجام میدیم:



use northwind
go

select orderdate,customerid,orderid from orders
go


قبل از انجام Query بعدی، کاربر دیگه ای ایندکسی میسازه و بعد دوباره به این روش Query میگیریم:



create index ix1 on orders(customerid,orderid,orderdate)
go

select * from
(select orderdate,customerid,orderid from orders) tmp


نتیجه Query اول و دوم متفاوته. تنها چیزی که یکسان بودن نتیجه این دو Query رو تضمین میکنه، استفاده از Order By هست. دقت کنید که در حالت Subquery، بیرونی ترین Query باید Order By انجام بده.
سئوال دیگر اگر کوئری زیر را داشته باشیم


create index ix1 on orders(customerid,orderid,orderdate)
go
(select orderdate,customerid,orderid from orders)
select * from
(select orderdate,customerid,orderid from orders) tmp

می‌توانیم ضمانت کنیم که دو select داده شده در کوئری فوق نتیجه یکسان خواهند داشت؟
بنظرم این مسئله بسیار مهم است. تنها جایی که قطع به یقین می‌توانیم قسم بخوریم که در پایگاه داده‌ای که از لحاظ ساختار و داده تغییر نکرده، اطلاعاتی که از پایگاه داده با دستور select خوانده می‌شود با اجرای چندباره تغییر نمی‌کند، آن جایی است که ترتیب دلخواه روی ستون‌هایی که با یکدیگر یکتا (Unique) شده‌اند(در یک قید یکتایی (Unique Constraint)) وجود داشته باشد. ولی در حالت کلی لزوما این اتفاق نمی‌افتد که من بخواهم روی ستون‌هایی که یکتا شده‌اند ترتیب بگذارم. به این دلیل روی خروجی یکسان دو کوئری اصرار دارم.

AminSobati
شنبه 07 دی 1387, 16:17 عصر
و این کوئری رو در query analyzer باز کنم و روی آن دو بار F5 بزنم بدون این‌که در پایگاه داده
northwind چه در ساختار چه در داده کوچک‌ترین دخل و تصرفی کنم می‌توانم توقع داشته باشم که نتیجه یکسان ببینم یا نه.


درسته که به احتمال 99.99 درصد یک نتیجه بدست میارین، اما چون Order BY ندارین، تغییر روی ایندکسها میتونه باعث بشه نتیجه تغییر کنه



می‌توانیم ضمانت کنیم که دو select داده شده در کوئری فوق نتیجه یکسان خواهند داشت؟

باز هم به احتمال زیاد نتیجه یکسان خواهند بود ولی از ایندکس تاثیر میگیرند.
توجه داشته باشید که وقتی Order By داشته باشیم میشه تضمین کرد نتیجه یکسانه حتی اگر ساختار جدول یا ایندکسها تغییر کنند. ولی اگر Data تغییر کنه نه. بدیهیه تغییر Data توی Sort تغییر ایجاد میکنه و اون ملاک نیست. بحث ما در حالتیه که روی یک Data قضاوت میکنیم

AminSobati
شنبه 07 دی 1387, 16:29 عصر
سلام
جناب ثباتی تشکر

از اون کد استفاده کردم احتمالا درست این کار رو انجام ندادم یا ...
چون تمام رکوردها رو برگردوند
اون index کارش چیه؟

حالا اگر به 10 یا 20 یا x تعداد رکورد آخر احتیاج باشه چی ؟


با تشکر

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

Sal_64
دوشنبه 09 دی 1387, 19:39 عصر
سلام

این کد رو ببینید
با اولین f5 ایررور میده که این تیبل وجود نداره
و با دومین f5 میگه این تیبل وحود داره و امکان ساخت مجددش نیست

لطفا ببینید

create table #dert3
(
name_dastgah nvarchar(50),
radif_dastgah varchar(50),
y int IDENTITY(1,1) NOT NULL,
)

SET IDENTITY_INSERT #dbo.dert3 ON

insert into #dert3 (name_dastgah ,radif_dastgah, y)
(
select * from cod with(index(0))
)

select name_dastgah ,radif_dastgah from
(select row_number() over(order by y) as MyRank,* from #dert3
)tmp
where MyRank between 4 and 6

drop table #dert3
مشکل چیه؟

با تشکر

تولائی
سه شنبه 10 دی 1387, 00:19 صبح
بجای



SET IDENTITY_INSERT #dbo.dert3 ON


بنویس



SET IDENTITY_INSERT #dert3 ON

dao. توش اضافه‌س
واقعا می‌خوای چی‌کار کنی؟

Sal_64
سه شنبه 10 دی 1387, 20:43 عصر
سلام


واقعا می خواید چی کار کنید؟کاری که جناب ثباتی گفتن
این

اون کد فقط از روی ترتیب ورود اطلاعات به شما نتیجه میده ولی همه رو برمیگردونه. مگر اینکه داخل یک جدول موقتی با Identity بریزید تا بتونین Range خاصی رو بدست بیارینهنوز ایررور پا برجاست
اول که میگه این تیبل موجوده
و زمانی که می خوام drop کنم اجازه نمیده
باقی تیبل های مجازی رو می تونم حذف کنم ولی این یکی نه

چه باید کرد ؟

با تشکر

تولائی
سه شنبه 10 دی 1387, 22:16 عصر
سلام

کاری که جناب ثباتی گفتن
این
هنوز ایررور پا برجاست
اول که میگه این تیبل موجوده
و زمانی که می خوام drop کنم اجازه نمیده
باقی تیبل های مجازی رو می تونم حذف کنم ولی این یکی نه

چه باید کرد ؟

با تشکر

شاید منظورت این کده


declare @tbl Table(rownumber int NOT NULL IDENTITY(1, 1),
name_dastgah nvarchar(50),
radif_dastgah varchar(50)
)
insert into @tbl select * from cod with(index(0))
select rownumber from @tbl where rownumber between 4 and 6


این‌طوری یک جدول موقت تعریف می‌شه وقتی کارمون تموم شد خودش حذف می‌شه.

AminSobati
جمعه 13 دی 1387, 01:53 صبح
به فیلد Identity نیاز نیست مقدار بدین. پست شماره 27 کمکتون نکرد؟