Django many to one reverse query on the same field - sql

I have a one to many relationship between two tables ...
Item - id, title
ItemAttribute - id, item_id, attribute_code(string, indexed)
where attribute_code can have values for colors, sizes, qualities, dimensions, etc,
- like codes for 'Blue', 'Black', 'White', 'S', 'L', 'XL', '250g', '400g', etc
Question: How do I query for all Items that are either ('Blue' OR 'White') AND 'XL'
I prefer using Django's ORM, but if someone could even help out with raw SQL it would do just fine. Thanks.

This subquery:
select item_id
from item_attribute
group by item_id
having sum(attribute_code in ('Blue', 'White')) > 0 and sum(attribute_code = 'XL') > 0
returns all the item_ids that you want.
So you can join it to the table item:
select i.*
from item i inner join (
select item_id
from item_attribute
group by item_id
having sum(attribute_code in ('Blue', 'White')) > 0 and sum(attribute_code = 'XL') > 0
) a on a.item_id = i.id
or use the operator IN:
select *
from item
where id in (
select item_id
from item_attribute
group by item_id
having sum(attribute_code in ('Blue', 'White')) > 0 and sum(attribute_code = 'XL') > 0
)
If you have really large data sets you could also try EXISTS:
select i.*
from item i
where
exists (select 1 from item_attribute where item_id = i.id and attribute_code in ('Blue', 'White'))
and
exists (select 1 from item_attribute where item_id = i.id and attribute_code = 'XL')

Related

How to display null values in IN operator for SQL with two conditions in where

I have this query
select *
from dbo.EventLogs
where EntityID = 60181615
and EventTypeID in (1, 2, 3, 4, 5)
and NewValue = 'Received'
If 2 and 4 does not exist with NewValue 'Received' it shows this
current results
What I want
Ideally you should maintain somewhere a table containing all possible EventTypeID values. Sans that, we can use a CTE in place along with a left join:
WITH EventTypes AS (
SELECT 1 AS ID UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5
)
SELECT et.ID AS EventTypeId, el.*
FROM EventTypes et
LEFT JOIN dbo.EventLogs el
ON el.EntityID = 60181615 AND
el.NewValue = 'Received'
WHERE
et.ID IN (1,2,3,4,5);

Insert occasionally missing rows

I am running below query, sometimes these query skip few records to insert into newordersholdentry and didn't get any error.
but if run same query again after finding it is missed some records for order, it will insert all.
Please let me know what could be the reason.
INSERT INTO newordersholdentry
(itemid,
lookupcode,
description,
gamacode,
ordered,
IsForceItem,
Scanned,
Location,
SortOrder
)
SELECT ID,
ItemLookupCode,
Description,
GamaCode,
SUM(Qty) AS Qty,
ForceItem,
0 AS Scanned,
SubDescription1,
Sortorder
FROM
(
SELECT Item.ID,
Item.ItemLookupCode,
Item.Description,
NewOrderItems.GamaCode,
NewOrderItems.Qty,
Item.SubDescription1,
Item.Binlocation,
ISNULL(
(
SELECT TOP (1) SortSno
FROM NewOrderPickPackSorting
WHERE(Bin = LEFT(Item.SubDescription1, 3))
), 99999) AS Expr1,
0 AS ForceItem,
p.sortorder
FROM NewOrderItems(NOLOCK)
INNER JOIN Item(NOLOCK) ON NewOrderItems.GamaCode = Item.SubDescription2
LEFT OUTER JOIN pickpath(NOLOCK) p ON concat(RTRIM(p.aisle), '-', p.section) = UPPER(LEFT(item.subdescription1, 6))
WHERE(NewOrderItems.Discontinue = 0)
AND (NewOrderItems.OrderID = 123456)
) AS t
Group by ID
, ItemLookupcode
, Description
, GAMACODE
, ForceItem
, Expr1
, BinLocation
, SubDescription1
, sortorder

SQL equivalent "$all" MongoDB operator on Repeated string

Suppose the following Data structure:
MongoDB: {id: ObjectId, colors: String[]}
SQL: Column ID (Integer), Column COLORS (Repeated String)
Suppose the following MongoDB query:
collection.find({colors: {$all: ["blue", "orange", "yellow"]} })
What is the equivalent operator/notation for "$all" in SQL? Notice that different from the $in, $all looks for documents (rows) having that field matching ALL the values, not only "some" of them.
Assuming there are no duplicates in the repeated values, you can use:
select s.*
from sql s
where (select count(*)
from unnest(s.colors) color
where color in ('blue', 'orange', 'yellow')
) = 3;
The "3" is the size of the list. If there are duplicates, then use count(distinct color) instead.
If you don't want to "remember" 3, you can use:
with color_list as (
select color
from unnest(array['blue', 'orange', 'yellow']) color
)
select s.*
from sql s
where (select count(*)
from unnest(s.colors) color join
color_list cl
using (color)
) = (select count(*) from color_list);
Or even:
select s.*
from sql s
where not exists (select 1
from unnest(array['blue', 'orange', 'yellow']) my_color left join
unnest(s.colors) color
on my_color = color
where color is null
);
Below is for BigQuery Standard SQL
#standardSQL
create temp function check_all(arr ANY TYPE, match ANY TYPE) as (
array_length(array(
select distinct m from unnest(match) m
join unnest(arr) m using(m)
)) = array_length(array(
select distinct m from unnest(match) m
))
);
select *
from `project.dataset.table`
where check_all(colors, ['blue', 'orange', 'yellow'])
if to apply to below dummy sample data
with `project.dataset.table` as (
select 1 id, ['blue', 'orange', 'yellow', 'black'] colors union all
select 2, ['blue', 'pink', 'yellow', 'green'] union all
select 3, ['red', 'orange', 'blue', 'pink', 'yellow', 'green']
)
the output is

Count Joins from Multiple Tables

For reference, I am using Postgres 9.2.23.
I have several tables where one table (user_group) is related to some other tables (eg: posts, group_invites, and some more other ones). There is, also a groups table, but it doesn't hold any data that I need for the purposes of these queries.
Table user_group:
fk_user_group_id, fk_user_id, fk_group_id, fk_invite_id user_status, ...
Table message:
pk_message_id, fk_user_id, fk_group_id, child_message_id, ...
Table group_prospective_user:
pk_prospective_user_id, fk_group_id, ...
I want to get some statistics for each of the related tables for a list of specified group ids if the user is a member of the group.
Right now I do this with one query for each related table, eg:
select
"public"."user_group"."fk_group_id" as "groupId",
count(case
when (
"public"."message"."child_message_id" is null
and "public"."message"."pk_message_id" is not null
) then "public"."message"."pk_message_id"
end) as "numDiscussions",
count("public"."message"."pk_message_id") as "numDiscussionPosts"
from "public"."user_group"
left outer join "public"."message"
on "public"."message"."fk_group_id" = "public"."user_group"."fk_group_id"
where (
"public"."user_group"."fk_group_id" in (
1, 11, 23, 530, 1070
)
and "public"."user_group"."role" in (
'ADMINISTRATOR', 'MODERATOR', 'MEMBER'
)
and "public"."user_group"."fk_user_id" = 17517
)
group by "public"."user_group"."fk_group_id"
And for invites:
select
"public"."user_group"."fk_group_id" as "groupId",
count(case
when "public"."prospective_user"."status" = 1 then "public"."prospective_user"."pk_prospective_user_id"
end) as "numInviteesExternal"
from "public"."user_group"
left outer join "public"."prospective_user"
on "public"."prospective_user"."fk_group_id" = "public"."user_group"."fk_group_id"
where (
"public"."user_group"."fk_group_id" in (
1, 11, 23, 530, 6176
)
and "public"."user_group"."role" in (
'ADMINISTRATOR', 'MODERATOR', 'MEMBER'
)
and "public"."user_group"."fk_user_id" = 17517
)
group by "public"."user_group"."fk_group_id"
The query to count the number of group invites is very similar to the above query. Just the count when and join on change.
Each of the queries to these tables has the same related logic for checking the groups to which the current user is an active member. Is there efficient way to merge multiple similar queries like this into a single query?
I tried using multiple LEFT JOINs with select count distinct, but that ran into performance issues on groups with both lots of messages, and lots of invites. Is there a way to easily/efficiently do this with, say, a subquery?
The answer from user #Parfait was the most scalable solution I could find. I based my queries on this tutorial: https://www.sqlteam.com/articles/using-derived-tables-to-calculate-aggregate-values.
While this isn't perfect, and results in a bunch of subqueries running, it does get me all the data at once, and with a single trip to the DB.
It ended up like this:
"groups"."groupId",
coalesce(
"members"."member_count",
0
) as "numActiveMembers",
coalesce(
"members"."invitee_count",
0
) as "numInviteesInternal",
coalesce(
"discussions"."discussions_count",
0
) as "numDiscussions",
coalesce(
"discussions"."posts_count",
0
) as "numDiscussionPosts"
from (
select "public"."user_group"."fk_group_id" as "groupId"
from "public"."user_group"
where (
"public"."user_group"."fk_group_id" in (
1, 2, 3, 4, 5
)
and "public"."user_group"."role" = 'ADMINISTRATOR'
and "public"."user_group"."fk_user_id" = 123
)
group by "public"."user_group"."fk_group_id"
) as "groups"
left outer join (
select
"public"."user_group"."fk_group_id" as "members_group_id",
count(distinct case
when "public"."user_group"."role" in (
'ADMINISTRATOR', 'MODERATOR', 'MEMBER'
) then "public"."user_group"."pk_user_group_id"
end) as "member_count",
count(distinct case
when "public"."user_group"."role" = 'INVITEE' then "public"."user_group"."pk_user_group_id"
end) as "invitee_count"
from "public"."user_group"
group by "public"."user_group"."fk_group_id"
) as "members"
on "members_group_id" = "groupId"
left outer join (
select
"public"."message"."fk_group_id" as "discussions_group_id",
count(case
when (
"public"."message"."child_message_id" is null
and "public"."message"."pk_message_id" is not null
) then "public"."message"."pk_message_id"
end) as "discussions_count",
count("public"."message"."pk_message_id") as "posts_count"
from "public"."message"
group by "public"."message"."fk_group_id"
) as "discussions"
on "discussions_group_id" = "groupId"```

how do i get multiple records from 1 record

I have a product table with 15 fields like ItemID (primary),Name ,UPC,Price,Cost, etc.
Now I need to print labels the user can say
from Item "ABC" I need 15 labels
from item 'XYZ" I need 10 labels
I need a SQL statement which I will send the ItemID and the label Qty for Each record and it should give me back for each label a record for example 15 records for item "ABC" and 10 records for Item "XYZ" and so on
SELECT <fields>
FROM Mytable
Where Item = 'ABC'
GO 10
Will select those fields from that table 10 times in a row in 10 result sets.
Really though it sounds like you need to do what you are trying to do not in SQL, but in your calling application.
I agree this should be done on the client but if you insist, following duplicates each record 100 times and selects the amount you need from it.
;WITH ATable AS (
SELECT Item = 'ABC'
UNION ALL SELECT Item = 'XYZ'
)
, Temp (Item, Amount) AS (
SELECT 'ABC', 15
UNION ALL SELECT 'XYZ', 10
)
, q AS (
SELECT ID = 1
, Item
FROM ATable
UNION ALL
SELECT ID = q.ID +1
, q.Item
FROM q
WHERE ID < 100
)
SELECT q.*
FROM q
INNER JOIN Temp t ON t.Item = q.Item
AND t.Amount >= q.ID
You create the dynamic table aliased as r below. Works for amounts up to 2047.
select t.*
from
(select label='ABC', required=15 union all
select label='XYZ', required=10) r
inner join tbl t
on t.ItemID = r.label
inner join master..spt_values v
on v.type=Number and v.number between 1 and r.required
order by t.ItemID