শূন্যের চেয়ে বড় কোনও সংস্থার গণনা রয়েছে এমন সমস্ত রেকর্ড খুঁজুন


100

আমি এমন কিছু করার চেষ্টা করছি যা আমি ভেবেছিলাম এটি সহজ হবে তবে এটি মনে হয় না।

আমার একটি প্রকল্পের মডেল রয়েছে যার অনেক শূন্যপদ রয়েছে।

class Project < ActiveRecord::Base

  has_many :vacancies, :dependent => :destroy

end

আমি কমপক্ষে 1 টি শূন্যপদে থাকা সমস্ত প্রকল্প পেতে চাই। আমি এরকম কিছু চেষ্টা করেছি:

Project.joins(:vacancies).where('count(vacancies) > 0')

কিন্তু এটা বলে

SQLite3::SQLException: no such column: vacancies: SELECT "projects".* FROM "projects" INNER JOIN "vacancies" ON "vacancies"."project_id" = "projects"."id" WHERE ("projects"."deleted_at" IS NULL) AND (count(vacancies) > 0)

উত্তর:


68

joinsডিফল্ট হিসাবে একটি অভ্যন্তরীণ যোগদান ব্যবহার করে সুতরাং Project.joins(:vacancies)কার্যকরভাবে কেবলমাত্র এমন প্রকল্পগুলি প্রত্যাবর্তন করবে যা সম্পর্কিত শূন্যতা রয়েছে।

হালনাগাদ:

মন্তব্যটিতে @ ম্যাক্সকাটজ দ্বারা চিহ্নিত হিসাবে, কোনও groupধারা ছাড়াই , উপরের কোডটি একাধিক শূন্যপদ সহ প্রকল্পগুলির জন্য নকল প্রকল্পগুলি ফিরিয়ে দেবে। সদৃশ অপসারণ করতে, ব্যবহার করুন

Project.joins(:vacancies).group('projects.id')

হালনাগাদ:

@ টলসির নির্দেশ অনুসারে, আপনি এটিও ব্যবহার করতে পারেন distinct

Project.joins(:vacancies).distinct

উদাহরণ হিসাবে

[10] pry(main)> Comment.distinct.pluck :article_id
=> [43, 34, 45, 55, 17, 19, 1, 3, 4, 18, 44, 5, 13, 22, 16, 6, 53]
[11] pry(main)> _.size
=> 17
[12] pry(main)> Article.joins(:comments).size
=> 45
[13] pry(main)> Article.joins(:comments).distinct.size
=> 17
[14] pry(main)> Article.joins(:comments).distinct.to_sql
=> "SELECT DISTINCT \"articles\".* FROM \"articles\" INNER JOIN \"comments\" ON \"comments\".\"article_id\" = \"articles\".\"id\""

4
তবে, ধারা দ্বারা কোনও গ্রুপ প্রয়োগ না করে এটি এমন একাধিক শূন্যপদযুক্ত প্রকল্পগুলির জন্য একাধিক প্রকল্প বস্তুগুলি ফিরিয়ে আনবে।
mackshkatz

4
যদিও একটি দক্ষ এসকিউএল বিবৃতি উত্পন্ন করে না।
ডেভিড অ্যালড্রিজে

ওয়েল এটি আপনার জন্য রেলস। যদি আপনি কোনও বর্গোত্তর উত্তর সরবরাহ করতে পারেন (এবং ব্যাখ্যা করুন কেন এটি দক্ষ নয়) তবে এটি অনেক বেশি সহায়ক হতে পারে।
jvnill

আপনি কি সম্পর্কে মনে করেন Project.joins(:vacancies).distinct?
টোলসি

4
এটি @ টোলসি বিটিডব্লিউ: ডি
টোলসি

172

1) কমপক্ষে 1 টি শূন্যপদে প্রকল্পগুলি পেতে:

Project.joins(:vacancies).group('projects.id')

2) 1 টিরও বেশি শূন্যপদে প্রকল্পগুলি পেতে:

Project.joins(:vacancies).group('projects.id').having('count(project_id) > 1')

3) অথবা, যদি Vacancyমডেল কাউন্টার ক্যাশে সেট করে:

belongs_to :project, counter_cache: true

তাহলে এটিও কার্যকর হবে:

Project.where('vacancies_count > ?', 1)

জন্য আনতি নিয়ম vacancyকরা প্রয়োজন হতে পারে নিজে নিদিষ্ট ?


4
এটা কি হওয়া উচিত নয় Project.joins(:vacancies).group('projects.id').having('count(vacancies.id) > 1')? প্রকল্প
আইডির

4
না, @ কিথম্যাটিক্স, এটি হওয়া উচিত নয়। এটি হতে পারে, যদি এটি আপনার কাছে আরও ভাল পড়ে; এটা পছন্দসই বিষয়। যোগদানের টেবিলের যে কোনও ক্ষেত্রের সাথে প্রতিটি সারিতে একটি মান থাকার গ্যারান্টিযুক্ত গণনা করা যেতে পারে। সর্বাধিক অর্থপূর্ণ প্রার্থীদের projects.id, project_idএবং vacancies.id। আমি গণনা করা বেছে নিয়েছি project_idকারণ এটি সেই ক্ষেত্র যার ভিত্তিতে যোগদান করা হয়; আপনি যদি যোগদানের মেরুদণ্ড। এটি আমাকে মনে করিয়ে দেয় যে এটি একটি যোগদানের টেবিল।
আরতা

38

হ্যাঁ, vacanciesযোগ দেওয়ার কোনও ক্ষেত্র নয়। আমি বিশ্বাস করি আপনি চান:

Project.joins(:vacancies).group("projects.id").having("count(vacancies.id)>0")

16
# None
Project.joins(:vacancies).group('projects.id').having('count(vacancies) = 0')
# Any
Project.joins(:vacancies).group('projects.id').having('count(vacancies) > 0')
# One
Project.joins(:vacancies).group('projects.id').having('count(vacancies) = 1')
# More than 1
Project.joins(:vacancies).group('projects.id').having('count(vacancies) > 1')

6

একটি_এর সাথে মিলিত has_many টেবিলের সাথে অভ্যন্তরীণ যোগদান সম্পাদন করা groupবা uniqসম্ভাব্যভাবে খুব অদক্ষ, এবং এসকিউএল এ এটি একটি আধা-যোগ হিসাবে আরও ভালভাবে প্রয়োগ করা হবে যা EXISTSসম্পর্কিত সম্পর্কযুক্ত সাবকোয়ারির সাথে ব্যবহার করে ।

এটি কোয়েরি অপটিমাইজারকে শূন্যপদগুলির সারণীটি সঠিক প্রোজেক্ট_আইড দিয়ে সারিটির অস্তিত্বের জন্য তদন্ত করতে সহায়তা করে। এক সারি বা মিলিয়ন যে প্রকল্প_আইড আছে তা বিবেচনা করে না।

এটি কারাগারে সহজ সরল নয়, তবে এটি দ্বারা অর্জন করা যেতে পারে:

Project.where(Vacancies.where("vacancies.project_id = projects.id").exists)

একইভাবে, এমন সমস্ত প্রকল্পগুলি সন্ধান করুন যার কোনও শূন্যপদ নেই:

Project.where.not(Vacancies.where("vacancies.project_id = projects.id").exists)

সম্পাদনা করুন: সাম্প্রতিক কালের সংস্করণগুলিতে আপনি একটি অবচয় হুঁশিয়ারি পেয়ে যাচ্ছেন যে আপনাকে existsআরএল- তে নিযুক্ত হওয়ার উপর নির্ভর করবেন না telling এটি দিয়ে এটি ঠিক করুন:

Project.where.not(Vacancies.where("vacancies.project_id = projects.id").arel.exists)

সম্পাদনা করুন: আপনি যদি কাঁচা এসকিউএল নিয়ে অস্বস্তি হন তবে চেষ্টা করুন:

Project.where.not(Vacancies.where(Vacancy.arel_table[:project_id].eq(Project.arel_table[:id])).arel.exists)

ব্যবহারকে আড়াল করার জন্য শ্রেণি পদ্ধতিগুলি যোগ করে আপনি এই কম অগোছালো করতে পারেন arel_table, উদাহরণস্বরূপ:

class Project
  def self.id_column
    arel_table[:id]
  end
end

... তাই ...

Project.where.not(
  Vacancies.where(
    Vacancy.project_id_column.eq(Project.id_column)
  ).arel.exists
)

এই দুটি প্রস্তাবনা কাজ বলে মনে হচ্ছে না ... subquery Vacancy.where("vacancies.project_id = projects.id").exists?উৎপাদনের পারেন trueবা falseProject.where(true)একটি ArgumentError
লেস

Vacancy.where("vacancies.project_id = projects.id").exists?কার্যকর করা হচ্ছে না - এটি ত্রুটি বাড়িয়ে তুলবে কারণ projectsসম্পর্কের সন্ধানটি কোয়েরিতে থাকবে না (এবং উপরে নমুনা কোডটিতে কোনও প্রশ্ন চিহ্ন নেই)। সুতরাং এটিকে দুটি অভিব্যক্তিতে বিভক্ত করা বৈধ নয় এবং কাজ করে না। সাম্প্রতিক কারাগারে Project.where(Vacancies.where("vacancies.project_id = projects.id").exists)একটি অবচয় হুঁশিয়ারি উত্থাপন করেছে ... আমি প্রশ্নটি আপডেট করব।
ডেভিড অলড্রিজ

4

4+ রেলগুলিতে, আপনি একই উত্তর পেতে অন্তর্ভুক্ত বা উত্সাহিত লোড ব্যবহার করতে পারেন :

Project.includes(:vacancies).references(:vacancies).
        where.not(vacancies: {id: nil})

Project.eager_load(:vacancies).where.not(vacancies: {id: nil})

4

আমি মনে করি একটি সহজ সমাধান আছে:

Project.joins(:vacancies).distinct

4
.Distinct: (খালি) এ ছাড়া "স্বতন্ত্র", যেমন Project.joins ব্যবহার করা সম্ভব
Metaphysiker

তুমি ঠিক! # ইউনিকের পরিবর্তে # ডিসিস্টিন্ট ব্যবহার করা ভাল। # ইউনীক সমস্ত বস্তুকে মেমোরিতে লোড করবে, তবে # ডিস্টিন্ট একটি ডাটাবেসের দিক থেকে গণনা করবে।
ইউরি কার্পোভিচ

3

প্রচুর রেল যাদু ছাড়াই আপনি এটি করতে পারেন:

Project.where('(SELECT COUNT(*) FROM vacancies WHERE vacancies.project_id = projects.id) > 0')

এই ধরণের শর্তগুলি সমস্ত রেল সংস্করণে কাজ করবে যতটা কাজ সরাসরি ডিবি সাইডে করা হয়। এছাড়াও, চেইন .countপদ্ধতি খুব সুন্দরভাবে কাজ করবে। আমি Project.joins(:vacancies)আগের মত প্রশ্ন দ্বারা পুড়েছি । অবশ্যই এটির বিভিন্ন উপকারিতা রয়েছে কারণ এটি ডিবি অজ্ঞায়নের নয়।


4
এটি যোগদান এবং গোষ্ঠী পদ্ধতির তুলনায় অনেক ধীর, কারণ 'নির্বাচন গণনা (*) ..' সাবকোয়ারি প্রতিটি প্রকল্পের জন্য কার্যকর করা হবে।
ইয়াসিরআজগার

@ ইয়াসিরআজগার যোগ দিন এবং গোষ্ঠী পদ্ধতিটি "বিদ্যমান" পদ্ধতির চেয়ে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে তা মিলিয়ে মিলিয়ন থাকলেও এটি সমস্ত শিশু সারিতে অ্যাক্সেস করবে।
ডেভিড অলড্রিজ

0

এছাড়াও আপনি ব্যবহার করতে পারেন EXISTSসঙ্গে SELECT 1থেকে সব কলাম নির্বাচন বদলে vacanciesটেবিল:

Project.where("EXISTS(SELECT 1 from vacancies where projects.id = vacancies.project_id)")

-6

ত্রুটিটি আপনাকে বলছে যে শূন্যপদগুলি মূলত প্রকল্পগুলির কোনও কলাম নয়।

এই কাজ করা উচিত

Project.joins(:vacancies).where('COUNT(vacancies.project_id) > 0')

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