কীভাবে রেলগুলিতে গতিশীল বাঁধাইয়ের সাথে কাঁচা আপডেট স্ক্যুয়েল চালানো যায়


102

আমি নীচের মত একটি আপডেট কাঁচা এসকিউএল সম্পাদন করতে চাই:

update table set f1=? where f2=? and f3=?

এই এসকিউএল দ্বারা কার্যকর করা হবে ActiveRecord::Base.connection.execute, তবে কীভাবে পদ্ধতিতে গতিশীল পরামিতি মানগুলি পাস করতে হয় তা আমি জানি না।

কেউ কি আমাকে এতে কোনও সহায়তা দিতে পারেন?


আপনি কাঁচা এসকিউএল ব্যবহার করে কেন এটি করতে চান, অ্যাক্টিভেকর্ডের বিষয়টি আপনাকে এড়াতে সহায়তা করার জন্য ...
অ্যান্ড্রু

আমি যদি এআর ব্যবহার করি তবে প্রথমে আমার আইডি ক্ষেত্রের সাথে আর এর সন্ধানের পদ্ধতি অনুসারে মডেল অবজেক্টটি পাওয়া উচিত, তারপরে আপডেট অপারেশন করা উচিত। সুতরাং অপারেশন দর্শন থেকে এক আপডেটের এআর ডাটাবেস সহ দুটি স্কয়ার প্রয়োজন; অন্যদিকে আমি নিশ্চিত নই যে এআর-এর আপডেট পদ্ধতিটি ডায়নামিক বাইন্ডিং ব্যবহার করে। সুতরাং আমি আপডেট অপারেশনের জন্য ডিবির সাথে একটি মিথস্ক্রিয়াটির জন্য গতিশীল বাঁধাইয়ের সাথে কাঁচা এসকিউএল ব্যবহার করতে চাই, তবে আমি কীভাবে প্রতিস্থাপনের জন্য প্যারামিটারগুলি পাস করব জানি না? এ।
ywenbo

27
এটি করার অনেকগুলি বৈধ কারণ রয়েছে। প্রথমত, ক্যোয়ারীটি নিয়মিত রুবি উপায় ব্যবহার করে অনুবাদ করা খুব জটিল হতে পারে ... দ্বিতীয়ত, প্যারামিটারগুলিতে%, বা উদ্ধৃতিগুলির মতো বিশেষ অক্ষর থাকতে পারে এবং
পাছার

4
@ অ্যান্ড্রু, এআর যে "সুবিধা" দেয় তার চেয়ে কাঁচা মাইএসকিএল ফাংশন ব্যবহার করা ভাল।
সবুজ

4
আপনি গ্রাহক হন না যদি আপনি কখনও মাইএসকিউএল থেকে পোস্টগ্র্রেএসকিউএল বা অন্য কোনও কিছুতে যেতে চান। একটি ORM এর অন্যতম প্রধান বিষয় হ'ল আপনার অ্যাপ্লিকেশনটিকে পোর্টেবল make
অ্যান্ড্রু

উত্তর:


103

দেখে মনে হচ্ছে না যে রেলস এপিআই সাধারণভাবে এটি করার পদ্ধতি প্রকাশ করে। আপনি অন্তর্নিহিত সংযোগটি অ্যাক্সেস করার এবং এর পদ্ধতিগুলি ব্যবহার করার চেষ্টা করতে পারেন, যেমন মাইএসকিউএল এর জন্য:

st = ActiveRecord::Base.connection.raw_connection.prepare("update table set f1=? where f2=? and f3=?")
st.execute(f1, f2, f3)
st.close

আমি নিশ্চিত নই যে এটি করার জন্য অন্যান্য পদক্ষেপ রয়েছে কিনা (সংযোগগুলি খোলা রয়েছে ইত্যাদি)। আমি আসল জিজ্ঞাসাটি বাদ দিয়ে কি করছে তা দেখার জন্য আমি একটি সাধারণ আপডেটের জন্য রেল কোডগুলি সন্ধান করব।

প্রস্তুত ক্যোয়ারীগুলি ব্যবহার করা আপনাকে ডাটাবেসে অল্প পরিমাণে সময় সাশ্রয় করতে পারে, তবে আপনি যদি একটানা এক মিলিয়ন বার এটি না করেন তবে আপনি সম্ভবত সাধারণ রুবির প্রতিস্থাপনের সাথে আপডেট তৈরির চেয়ে আরও ভাল better

ActiveRecord::Base.connection.execute("update table set f1=#{ActiveRecord::Base.sanitize(f1)}")

অথবা মন্তব্যকারীদের মত অ্যাক্টিভেকর্ড ব্যবহার করে ড।


26
প্রস্তাবিত "নরমাল রুবি সাবস্টিটিউশন" পদ্ধতিটি ব্যবহার করে সাবধান থাকুন এটি field=#{value}আপনাকে এসকিউএল ইনজেকশন আক্রমণে প্রশস্ত করে দেয়। আপনি যদি সেই পথে নামেন তবে অ্যাক্টিভেকর্ড :: সংযোগআডাপ্টারস :: উদ্ধৃতি মডিউলটি দেখুন।
পল আনিসলে

4
: দয়া করে নোট, mysql2 প্রস্তুত বিবৃতি সমর্থন করে না, তাও দেখতে stackoverflow.com/questions/9906437/...
reto

4
@ রিটো দেখে মনে হচ্ছে এগুলি যদিও কাছাকাছি: github.com/brianmario/mysql2/pull/289
ব্রায়ান ডিটারলিং

4
prepareমাইএসকিএল 2 তে কোনও বিবৃতি নেই
সবুজ

4
ডকুমেন্টেশন অনুসারে: "দ্রষ্টব্য: আপনার ডাটাবেস সংযোজকের উপর নির্ভর করে, এই পদ্ধতিতে ফিরে আসা ফলাফলটি ম্যানুয়ালি ম্যানেজ করা যেতে পারে instead পরিবর্তে #exec_query মোড়ক ব্যবহার করার বিষয়টি বিবেচনা করুন" " executeএটি বিপজ্জনক পদ্ধতি এবং মেমরি বা অন্যান্য উত্স লিকের কারণ হতে পারে।
kollen

33

ActiveRecord::Base.connectionএকটি quoteপদ্ধতি রয়েছে যা স্ট্রিংয়ের মান (এবং বিকল্পভাবে কলামের অবজেক্ট) নেয়। সুতরাং আপনি এটি বলতে পারেন:

ActiveRecord::Base.connection.execute(<<-EOQ)
  UPDATE  foo
  SET     bar = #{ActiveRecord::Base.connection.quote(baz)}
EOQ

নোট করুন যদি আপনি একটি রেল স্থানান্তর বা একটি অ্যাক্টিভেকর্ড অবজেক্টে থাকেন তবে আপনি এটি সংক্ষিপ্ত করতে পারেন:

connection.execute(<<-EOQ)
  UPDATE  foo
  SET     bar = #{connection.quote(baz)}
EOQ

আপডেট: @ কোলেন যেমন উল্লেখ করেছেন, আপনার exec_updateপরিবর্তে এটি ব্যবহার করা উচিত । এটি আপনার জন্য উদ্ধৃতি পরিচালনা করবে এবং মেমরি ফাঁস করা এড়াবে। স্বাক্ষরটি কিছুটা আলাদাভাবে কাজ করে যদিও:

connection.exec_update(<<-EOQ, "SQL", [[nil, baz]])
  UPDATE  foo
  SET     bar = $1
EOQ

এখানে শেষ প্যারামটি বাইন্ড প্যারামিটারগুলি উপস্থাপন করে এমন টিউপসগুলির একটি অ্যারে is প্রতিটি টিপলে প্রথম এন্ট্রিটি কলামের ধরণ এবং দ্বিতীয়টি মান। আপনি nilকলামের ধরণের জন্য দিতে পারেন এবং সাধারণভাবে যদিও রেলগুলি সঠিক কাজটি করে।

এছাড়াও রয়েছে exec_query, exec_insertএবং exec_deleteআপনার যা প্রয়োজন তার উপর নির্ভর করে।


4
ডকুমেন্টেশন অনুসারে: "দ্রষ্টব্য: আপনার ডাটাবেস সংযোজকের উপর নির্ভর করে, এই পদ্ধতিতে ফিরে আসা ফলাফলটি ম্যানুয়ালি ম্যানেজ করা যেতে পারে instead পরিবর্তে #exec_query মোড়ক ব্যবহার করার বিষয়টি বিবেচনা করুন" " executeএটি বিপজ্জনক পদ্ধতি এবং মেমরি বা অন্যান্য উত্স লিকের কারণ হতে পারে।
17

4
বাহ ভাল ক্যাচ! এখানে ডকুমেন্টেশন দেওয়া আছে । এছাড়াও পোস্টগ্র্রেস অ্যাডাপ্টার এখানে ফাঁস হবে বলে মনে হচ্ছে ।
পল এ জংউথर्थ

আশ্চর্য, যদি এআর on duplicate key updateসর্বত্র আমাদের জন্য কিছুই না ফেলে থাকে
শ্রীনাথ

4
@ শ্রীনাথ যেহেতু এই প্রশ্নটি কাঁচা এসকিউএল লেখার বিষয়ে, আপনি ON CONFLICT DO UPDATEযদি চান তবে আপনার ক্যোয়ারী তৈরি করতে পারে । অ-কাঁচা এসকিউএল-এর জন্য এই রত্নটি সুশোভিত
পল এ

4

আপনার যেমন কিছু ব্যবহার করা উচিত:

YourModel.update_all(
  ActiveRecord::Base.send(:sanitize_sql_for_assignment, {:value => "'wow'"})
)

কৌতুক করবে। ব্যবহার ActiveRecord :: বেজ # পাঠান ডাকা পদ্ধতি sanitize_sql_for_assignment তোলে রুবি (অন্তত 1.8.7 সংস্করণ) সত্য যে লাফালাফি sanitize_sql_for_assignment আসলে একটি সংরক্ষিত পদ্ধতি।


2

কিছু সময় টেবিলে পরিবর্তে অভিভাবক শ্রেণীর নাম ব্যবহার করা ভাল better

# Refers to the current class
self.class.unscoped.where(self.class.primary_key => id).update_all(created _at: timestamp)

উদাহরণস্বরূপ "ব্যক্তি" বেস ক্লাস, সাবক্লাস (এবং ডাটাবেস টেবিল) "ক্লায়েন্ট" এবং "বিক্রেতা" এর পরিবর্তে ব্যবহার করুন:

Client.where(self.class.primary_key => id).update_all(created _at: timestamp)
Seller.where(self.class.primary_key => id).update_all(created _at: timestamp)

আপনি বেস ক্লাসের অবজেক্টটি এভাবে ব্যবহার করতে পারেন:

person.class.unscoped.where(self.class.primary_key => id).update_all(created _at: timestamp)

1

এর জন্য কাঁচা এসকিউএল কেন ব্যবহার করবেন?

আপনি একটি মডেল থাকে, তাহলে তা ব্যবহার where:

f1 = 'foo'
f2 = 'bar'
f3 = 'buzz'
YourModel.where('f1 = ? and f2 = ?', f1, f2).each do |ym|
  # or where(f1: f1, f2: f2).each do (...)
  ym.update(f3: f3) 
end

যদি আপনার কাছে এটির জন্য কোনও মডেল না থাকে (কেবল টেবিল) তবে আপনি এমন একটি ফাইল এবং মডেল তৈরি করতে পারেন যা উত্তরাধিকার সূত্রে প্রাপ্ত হবেActiveRecord::Base

class YourTable < ActiveRecord::Base
  self.table_name = 'your_table' # specify explicitly if needed
end

এবং আবার whereউপরের মত একই ব্যবহার করুন:


4
এটি এত কম দক্ষ, তাই না? এই নির্বাচনের জন্য কি এক আপডেটের বিবৃতিটি ট্রেড করে না, রেলগুলি মেমরির মধ্যে রেকর্ডগুলি নিয়ে আসে, প্রতিটি রেকর্ড আপডেট করে এবং প্রতিটি রেকর্ডের জন্য একটি আপডেট বিবৃতি পাঠায়। 1 আপডেট বনাম 1 প্রতি রেকর্ড এবং অনেক ব্যান্ডউইথ, ইত্যাদি? এআর কি এটি অপ্টিমাইজ করে বা না? আমি মনে করি না এটি হয়।
জিমি

0

এখানে একটি কৌশল যা আমি সম্প্রতি কাঁচা এসকিউএলকে বাইন্ড সহ কার্যকর করার জন্য কাজ করেছি:

binds = SomeRecord.bind(a_string_field: value1, a_date_field: value2) +
        SomeOtherRecord.bind(a_numeric_field: value3)
SomeRecord.connection.exec_query <<~SQL, nil, binds
  SELECT *
  FROM some_records
  JOIN some_other_records ON some_other_records.record_id = some_records.id
  WHERE some_records.a_string_field = $1
    AND some_records.a_date_field < $2
    AND some_other_records.a_numeric_field > $3
SQL

যেখানে এটি ApplicationRecordসংজ্ঞায়িত:

# Convenient way of building custom sql binds
def self.bind(column_values)
  column_values.map do |column_name, value|
    [column_for_attribute(column_name), value]
  end
end

এবং এটি কীভাবে এর নিজস্ব প্রশ্নের সাথে যুক্ত হয় তার অনুরূপ।


-11

আমার কাঁচা এসকিউএল ব্যবহার করা প্রয়োজন কারণ আমি অ্যাক্টিভরেকর্ড ২.৩.৮ নিয়ে কাজ করতে সম্মিলিত_প্রিমিয়ার_কিগুলি পেতে ব্যর্থ হয়েছি। সুতরাং একটি সমন্বিত প্রাথমিক কী সহ স্কেলসারভার 2000 টেবিলটি অ্যাক্সেস করতে, কাঁচা এসকিউএল প্রয়োজন ছিল।

sql = "update [db].[dbo].[#{Contacts.table_name}] " +
      "set [COLUMN] = 0 " +
      "where [CLIENT_ID] = '#{contact.CLIENT_ID}' and CONTACT_ID = '#{contact.CONTACT_ID}'"
st = ActiveRecord::Base.connection.raw_connection.prepare(sql)
st.execute

আরও ভাল সমাধান পাওয়া যায়, তাহলে শেয়ার করুন।


11
স্কয়ার-ইনজেকশন এখানে সম্ভব!
mystdeim

-21

রেল ৩.১ এ আপনার ক্যোয়ারী ইন্টারফেসটি ব্যবহার করা উচিত:

  • নতুন (বৈশিষ্ট্য)
  • তৈরি করুন (গুণাবলী)
  • তৈরি করুন!
  • (id_or_array) সন্ধান করুন
  • ধ্বংস করুন (id_or_array)
  • সর্বনাশের_
  • মুছে দিন (id_or_array)
  • সব মুছে ফেলুন
  • আপডেট (আইডি, আপডেট)
  • আপডেট_এল (আপডেট)
  • বিদ্যমান?

আপডেট এবং আপডেট_এল আপনার প্রয়োজনীয় অপারেশন।

এখানে বিশদটি দেখুন: http://m.onkey.org/active-record-query-interface

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.