اذهب إلى المحتوى

السؤال

نشر

لدي النماذج التالية

class Task(models.Model):
    project = models.ForeignKey(Project, on_delete=models.CASCADE)
    author = models.ForeignKey(User, on_delete=models.CASCADE)

class Project(models.Model):
    name = models.CharField(max_length=128)

class EmployeeProject(models.Model):
    project = models.ForeignKey(
        Project,
        on_delete=models.CASCADE,
        related_name='employee_projects',
    )
    employee = models.ForeignKey(Employee, on_delete=models.CASCADE)
    role = models.ForeignKey(ProjectRole, on_delete=models.CASCADE)
    skill_level = models.ForeignKey(SkillLevel, on_delete=models.CASCADE)
    hourly_rate = models.DecimalField(decimal_places=2, max_digits=9)

class TaskRole(LogOnSaveMixin, DiffModel):
    task = models.ForeignKey(
       Task, on_delete=models.CASCADE,
       related_name='roles',
    )
    estimated_hours = models.FloatField(null=True, blank=True)

الاستعلامات

qs = Task.objects.all()


user = self.request.user
host_roles = EmployeeProject.objects.filter(
      employee=user.employee,
)
qs = qs.annotate(
    total_estimated_hours=Sum('roles__estimated_hours'),
)
open_tasks_qs = qs.filter(
   Q(project__in=host_roles.values('project_id')),
 ).filter(
            (
                Q(total_estimated_hours__isnull=False)
            ),
        )

qs = open_tasks_qs | qs.filter(author=user).distinct()
qs = qs.values('id')
qs = qs.distinct()
return qs

المشكلة هي أن هذا الاستعلام ينتج عنه خطأ 

more than one row returned by a subquery used as an expression

يبدو SQL المقابل كما يلي:

SELECT 
  DISTINCT "tasks_task"."id" 
FROM 
  "tasks_task" 
  LEFT OUTER JOIN "tasks_taskrole" ON (
    "tasks_task"."id" = "tasks_taskrole"."task_id"
  ) 
GROUP BY 
  "tasks_task"."id", 
  (
    SELECT 
      U0."project_id" 
    FROM 
      "tasks_employeeproject" U0 
    WHERE 
      U0."employee_id" = 1
  ) 
HAVING 
  (
    (
      "tasks_task"."project_id" IN (
        SELECT 
          U0."project_id" 
        FROM 
          "tasks_employeeproject" U0 
        WHERE 
          U0."employee_id" = 1
      ) 
      AND SUM(
        "tasks_taskrole"."estimated_hours"
      ) IS NOT NULL
    ) 
    OR "tasks_task"."author_id" = 1
  ) 
ORDER BY 
  "tasks_task"."id" DESC

هناك سؤالان:
كيف تصلح المشكلة؟
كيف يمكن أن يكون استعلام فرعي جزءا من عبارة group by؟ حاولت أن أجد وثائق SQL على جوجل ، لكنني لم أجد شيئا

Recommended Posts

  • 0
نشر

المشكلة الرئيسية في الاستعلام الحالي هي أنك تحاول استخدام استعلام فرعي (subquery) داخل عبارة GROUP BY. يتم تنفيذ الاستعلام الفرعي لكل صف في الجدول الرئيسي قبل أن يتم تجميع النتائج باستخدام GROUP BY، مما يؤدي إلى زيادة عدد الصفوف المسترجعة من الجدول الرئيسي وبالتالي يتم إثارة الخطأ "more than one row returned by a subquery used as an expression".

لحل هذه المشكلة، يمكنك تغيير الاستعلام للقيام بالحسابات الإضافية بشكل مستقل قبل تضمينها في الاستعلام الرئيسي. يمكنك القيام بذلك باستخدام subquery بشكل منفصل لحساب مجموع الساعات المقدرة ومن ثم استخدام هذه القيمة في الاستعلام الرئيسي. هنا كيف يمكن تحسين الاستعلام:

```python
from django.db.models import Sum, Q

qs = Task.objects.all()
user = self.request.user
host_project_ids = EmployeeProject.objects.filter(employee=user.employee).values('project_id')

# احسب مجموع الساعات المقدرة باستخدام subquery
subquery = TaskRole.objects.filter(task=OuterRef('pk')).values('task').annotate(
    total_estimated_hours=Sum('estimated_hours')
).values('total_estimated_hours')[:1]

qs = qs.annotate(total_estimated_hours=Subquery(subquery, output_field=FloatField()))

open_tasks_qs = qs.filter(
    Q(project__in=host_project_ids) | Q(total_estimated_hours__isnull=False)
).distinct()

qs = open_tasks_qs | qs.filter(author=user).distinct()
qs = qs.values('id').distinct()
return qs
```

هذا التحسين يستخدم Subquery لحساب مجموع الساعات المقدرة باستخدام استعلام فرعي بشكل منفصل، ثم يتم استخدام هذه القيمة في الاستعلام الرئيسي دون الحاجة إلى تضمينها في GROUP BY.

انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أجب على هذا السؤال...

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.

  • إعلانات

  • تابعنا على



×
×
  • أضف...