PDA

View Full Version : ترکیب دستور Select و Insert در یک کوئری



pezhvakco
دوشنبه 27 اردیبهشت 1389, 13:49 عصر
آیا میشه در یک کوئری مقدار بیش ترین مقدار یک Id را بدست بیاری و همزمان یکی به اون اضافه و از شماره حاصل یک سطر با شماره Id جدید ایجاد کنیم .

تمام این کارها با یک کوئری انجام بشه .

محمد سلیم آبادی
دوشنبه 27 اردیبهشت 1389, 14:41 عصر
INSERT INTO table_name(id)
SELECT MAX(id) + 1 FROM table_name

احمد سامعی
دوشنبه 27 اردیبهشت 1389, 18:45 عصر
سلام استاد مثل هميشه سريع ممنون

اما من دو تا مشكل دارم

اگر هيچ ركوردي تا حالا در جدول ثبت نشده باشه هيچ مقداري برگردانده نمي شود حتي null بايد چي كار كرد

و دوم اگر بخواهيم بر اساس يك زمان خواص مثلاً اول هر ماه اين فيلد از يك عدد خواص مثل يك يا هر عددي شروع كنيم چي كار بايد بكنيم

محمد سلیم آبادی
دوشنبه 27 اردیبهشت 1389, 19:01 عصر
سلام،
راجب بحث اول:

INSERT INTO t1 (ID)
SELECT CASE WHEN NOT EXISTS ( SELECT * FROM t1) THEN 1 ELSE (SELECT MAX(id) FROM t1) + 1 END

در مورد بحث دوم، روشی که من از آن استفاده می کنم کمک گرفتن از توابع Ranking مثل ROW_NUMBER هست.
مثل دستور زیر:

SELECT *, Rank = ROW_NUMBER() OVER(PARTITION BY Month ORDER BY id)
FROM table_name

احمد سامعی
دوشنبه 27 اردیبهشت 1389, 19:26 عصر
سلام باز هم ممنون

اما با دستور پست دوم فقط مي شه مقادير كه تو سلكت هست به عنوان ركورد جديد قرار داد
اما اگر قرار باشه فقط مقدار ID از اين سلكت استفاده كنيم و بقيه فيلدهاي جدول از كاربر بگيريم چي ؟
مثلاً يك جدول با ده فيلد داريم يكي اون ها ID و مي خواهيم يك ركورد اضافه كنيم و به همه اين ده فيلد مقدار بديم چي كار كني ؟

محمد سلیم آبادی
دوشنبه 27 اردیبهشت 1389, 22:13 عصر
INSERT INTO t1 (ID, col1, col2, col3, col4, .... )
SELECT CASE WHEN NOT EXISTS ( SELECT * FROM t1) THEN 1 ELSE (SELECT MAX(id) FROM t1) + 1 END AS id, @col1, @col2, @col3, @col4 , .....

محمد سلیم آبادی
سه شنبه 28 اردیبهشت 1389, 09:03 صبح
اگر هيچ ركوردي تا حالا در جدول ثبت نشده باشه هيچ مقداري برگردانده نمي شود حتي null بايد چي كار كرد
اینطور نیست. اگر هیچ سطری در جدول وجود نداشته باشه عبارت SELECT MAX(id) FROM t مقدار NULL را بر میگرداند.
در اینصورت راه ساده تر از CASE این هست که با تابع COALESCE یا ISNULL بررسی کنیم. در نتیجه عبارت ساده تر:

INSERT INTO table(id, col1, col2, ....)
SELECT COALESCE((SELECT MAX(id) + 1 FROM table), 1) AS id, @col1, @col2, .... ;

احمد سامعی
سه شنبه 05 مرداد 1389, 11:38 صبح
سلام، استاد در ادامه همین بحث یک سوال دیگه:

چطور می شه این شماره ID که در دستور SELECT دریافت کردیم در خروجی کوئری نشون بدیم؟ من می خوام شمارۀ ID رکورد را به عنوان شماره پیگیری به کاربر نشون بدم و یا در یک جای دیگه از اون برای اینزرت در یک جدول دیگه استفاده کنم (کلید رابط دو جدول هست)

این هم یکی از کدهایی که استفاده کردم :

Command.CommandText = "INSERT INTO myTable (ID, Fname, Lname) " +
"SELECT CASE WHEN NOT EXISTS (SELECT * FROM myTable) THEN 1 ELSE (SELECT MAX(ID) + 1 FROM myTable) END AS ID, @Fn, @Ln";

if (Command.ExecuteNonQuery() == 1)
{
IDataReader reader = Command.ExecuteReader();
if (reader.Read()) { Console.WriteLine(reader.GetValue(0)); }
}
اما هیچ مقداری برگشت نمی شه

محمد سلیم آبادی
سه شنبه 05 مرداد 1389, 11:46 صبح
چطور می شه این شماره ID که در دستور SELECT دریافت کردیم در خروجی کوئری نشون بدیم؟
سلام، اگر از 2005/2008 استفاده می کنید با کمک ماده OUTPUT (http://technet.microsoft.com/en-us/library/ms177564.aspx)به چیزی شبیه به شکل زیر عمل کنید:


INSERT INTO table_name
OUTPUT inserted.the_column
SELECT statement here

احمد سامعی
سه شنبه 05 مرداد 1389, 16:18 عصر
باز هم ممنون استاد اما یک مشکل !!!
من کد خودم به شکل زیر تغییر دادم

Command.CommandText = "INSERT INTO myTable OUTPUT INSERTED.* " +
"SELECT CASE WHEN NOT EXISTS (SELECT * FROM myTable) THEN 1 ELSE (SELECT MAX(id) FROM myTable) + 1 END AS ID, " +
"@fm,@lN";
if (Command.ExecuteNonQuery() == 1)
{
IDataReader reader = Command.ExecuteReader();
if (reader.Read()) { result = Convert.ToInt32(reader.GetValue(0)); }
else result = 0;
reader.Close();
}
با این کد دو تا رکورد اضافه می شه ولی شماره آخرین ID ثبت شده برگشت داده می شه و تابع هم یک بار اجرا می شه یعنی همین کوئری خودبه خود دو تا رکورد با ID پشت سر هم ایجاد می کنه و شماره دومی برمی گردونه ؟

اشکال کد از کجاست ؟

saeedr22
سه شنبه 05 مرداد 1389, 17:29 عصر
سلام استاد مثل هميشه سريع ممنون

اما من دو تا مشكل دارم

اگر هيچ ركوردي تا حالا در جدول ثبت نشده باشه هيچ مقداري برگردانده نمي شود حتي null بايد چي كار كرد

و دوم اگر بخواهيم بر اساس يك زمان خواص مثلاً اول هر ماه اين فيلد از يك عدد خواص مثل يك يا هر عددي شروع كنيم چي كار بايد بكنيم

SELECT isnull(MAX(id),0) + 1 FROM table_name

محمد سلیم آبادی
سه شنبه 05 مرداد 1389, 17:45 عصر
SELECT isnull(MAX(id),0) + 1 FROM table_name
گرچه من به این موضوع در پست شماره 7 اشاره کرده بودم.
اما چرا در همان تابع مقدار 1 را قرار ندادین. یعنی:
SELECT COALESCE(MAX(id), 1) AS Id FROM table_name


با این کد دو تا رکورد اضافه می شه ولی شماره آخرین ID ثبت شده برگشت داده می شه و تابع هم یک بار اجرا می شه یعنی همین کوئری خودبه خود دو تا رکورد با ID پشت سر هم ایجاد می کنه و شماره دومی برمی گردونه ؟
اشکال کد از کجاست ؟
کوئری که قرار دادین در قسمت SELECT تنها یک سطر باید برگردانده بشه چون مقادیر Scalar را SELECT کرده ایم. مشکل از کوئری فکر نمی کنم باشه.
چرا OUTPUT INSERTED.* استفاده کردین. بنویسین INSERTED.id

tdkhakpur
سه شنبه 05 مرداد 1389, 18:10 عصر
سلام به همگی
شرمنده که داخل تاپیک دوستان ارسال شد.
یک کوئری به این صورت لازم دارم داخل جدول دو ایندکس یکی برای name و id و دومی برای fam و id در نظر گرفته شده که id یونیک هست حالا سوال این هست که با چه کوئری میتوانم یک رکورد را بر اساس یک ایندکس بدست بیارم یعنی همه فیلدهای رکورد بدست بیاد
مثلا


select name from mytable;

یا یه چیزی تو این مایه ها؟
ممنون.

محمد سلیم آبادی
سه شنبه 05 مرداد 1389, 18:16 عصر
سلام به همگی
شرمنده که داخل تاپیک دوستان ارسال شد.
یک کوئری به این صورت لازم دارم داخل جدول دو ایندکس یکی برای name و id و دومی برای fam و id در نظر گرفته شده که id یونیک هست حالا سوال این هست که با چه کوئری میتوانم یک رکورد را بر اساس یک ایندکس بدست بیارم یعنی همه فیلدهای رکورد بدست بیاد
مثلا


select name from mytable;

یا یه چیزی تو این مایه ها؟
ممنون.
1. سوالت off topic هست که نباید این کار انجام بدین لطفا در یک تاپیک این سوال را مطرح کنید. و از پست مجدد پرهیز کنید.
2. سوال نامفهوم هست. باید یک نمونه از داده ها و یک نمونه از نتیجه مورد نظرتون را به نمایش بگذارین.

احمد سامعی
سه شنبه 05 مرداد 1389, 22:17 عصر
سلام

استاد سلیمی دستوراتی که در پست هفت دادید خطا سینتکس می داد نمی دونم چرا ؟ و اجرا نمی شد اما روشی که در پست 4 گفتید عملی شد برای همین من هم از همون استفاده کردم و وقتی که از INSERT.ID تنها استفاده می کنم بازم خطا می ده برای همین از اون کد پست 10 استفاده کردم اما متاسفانه هنوزم دو تا رکورد ثبت می کنه و نمی دونم چی کار کنم اگر این روش جواب نده مجبورم کلی کد به برنامه اضافه کنم

من خط به خط برنامه با بریک پوینت اجرا کردم یک بار بیشتر اجرا نمی شه اما دو رکورد می زنه و شماره دومی رو هم باز می گردونه !!!

احمد سامعی
چهارشنبه 06 مرداد 1389, 10:42 صبح
سلام

من از commandText استفاده می کردم این بار از SP استفاده کردم و مشکل ثبت دو رکورد حل شد اما هنوزم فقط راه حل پست 4 برای مشخص شدن خالی بودن جدول جواب می ده !؟ جالب ! قطعاً دو راه دیگر هم باید درست باشه اما چرا خطای سینتکس می ده نمی دانم !

محمد سلیم آبادی
چهارشنبه 06 مرداد 1389, 14:23 عصر
اما چرا خطای سینتکس می ده نمی دانم !
شما اون کوئری که می نویسین و خطا syntax میدهد را همراه با خطای دقیق آن پست کنید تا بتونیم بررسی کنیم مشکل را.