Help with a complex self referency query accross multiple colums - sql

I am having difficulties with a complicated (for me any way) query.
The table I'm querying has 3 colums, ClientID (int Not Null), ProductID (int Not Null) and ExpiryDate (smalldatetime nullable)
Given two client ID's Master and Consolidated I need to perform the following business logic to return a single data set:
Select the ClientID with the greater
expiry date for a product where expiry
dates for both clientIDs are not null
Select the ClientID with a null expiry
date for a product where one expiry is
null and the other not null
Select the MasterID for a product
where both expiry dates are null or
both expiry dates are the same.
I have tried the following, but get stuck...
Create Table #ProductSub (ClientID int NOT NULL,
ProductID int NOT NULL,
ExpiryDate smalldatetime)
/* In real life there is a Clustered Primary Key On ClientID and ProductID
Load Up Some Test Data */
Insert into #ProductSub Values (1, 100, null)
Insert into #ProductSub Values (2, 100, null)
Insert into #ProductSub Values (1, 101, null)
Insert into #ProductSub Values (2, 102, null)
Insert into #ProductSub Values (1, 200, null)
Insert into #ProductSub Values (2, 200, '2009-01-01')
Insert into #ProductSub Values (1, 300, '2009-01-01')
Insert into #ProductSub Values (2, 300, null)
Insert into #ProductSub Values (1, 400, '2009-01-01')
Insert into #ProductSub Values (2, 400, '2008-01-01')
Insert into #ProductSub Values (1, 500, '2008-01-01')
Insert into #ProductSub Values (2, 500, '2009-01-01')
Insert into #ProductSub Values (1, 600, '2009-01-01')
Insert into #ProductSub Values (2, 600, '2009-01-01')
--Select * from #ProductSub
Declare #MasterClient int,
#ConsolClient int
Select #MasterClient = 1, #ConsolClient = 2
Select * from #ProductSub t1
/* Use Master Client ID When Expiry Date is Null) */
Where (ClientID = #MasterClient and ExpiryDate is null)
/* Use Consol ClientID if Expiry Date is null nut Expiry Date for Master Client ID is not */
OR (ClientID = #ConsolClient and ExpiryDate is null and ProductID not in (
Select ProductID from #ProductSub t2
Where (ClientID = #MasterClient and ExpiryDate is null))
)
OR -- OH NO my head exploded
/* OR EXISTS (Select 1
from #ProductSub t3
)*/
Drop Table #ProductSub
/********** Expected Output ************************
ClientID ProductID ExpiryDate
1 100 NULL
1 101 NULL
2 102 NULL
1 200 NULL
2 300 NULL
1 400 2009-01-01 00:00:00
2 500 2009-01-01 00:00:00
1 600 2009-01-01 00:00:00
Any and all help greatly appreciated
EDIT: Although it sounds like it, this is not homework but a real life problem I am hoping to find a real life solution to, I could do this myself, but all my solutions are leading down the path to temp tables. I should point out the production environment is SQLServer 7!

Here I've moved the conditions to a subquery. The subquery joins the rows for Consol and Master, so you can access columns from both rows. The condition is still a little complex because either row can be missing.
select ps.*
from #ProductSub ps
inner join (
select
CASE
WHEN c.ClientID is null THEN m.ClientID
WHEN m.ClientID is null THEN c.ClientID
WHEN m.ExpiryDate is not null and c.ExpiryDate is not null THEN
CASE
WHEN c.ExpiryDate > m.ExpiryDate THEN c.ClientID
ELSE m.ClientID
END
WHEN m.ExpiryDate is null THEN m.ClientID
WHEN c.ExpiryDate is null THEN c.ClientID
ELSE m.ClientID
END as ClientId,
COALESCE(m.ProductId, c.ProductId) as ProductId
from #ProductSub m
full outer join #ProductSub c
on m.ProductID = c.ProductID
and m.ClientID <> c.ClientID
where IsNull(m.clientid,#MasterClient) = #MasterClient
and IsNull(c.clientid,#ConsolClient) = #ConsolClient
) filter
on filter.clientid = ps.clientid
and filter.productid = ps.productid
order by ps.ProductId

The question isn't clear, but as I interpret it, perhaps something like:
DECLARE #MasterExpiry smalldatetime, #ConsolExpiry smalldatetime
SELECT #MasterExpiry = ExpiryDate FROM #ProductSub WHERE ClientID = #MasterClient
SELECT #ConsolExpiry = ExpiryDate FROM #ProductSub WHERE ClientID = #ConsolClient
SELECT CASE
WHEN #MasterExpiry IS NULL AND #ConsolExpiry IS NULL THEN #MasterClient
WHEN #MasterExpiry IS NULL THEN #MasterClient
WHEN #ConsolExpiry IS NULL THEN #ConsolClient
WHEN #MasterExpiry >= #ConsolExpiry THEN #MasterClient
ELSE #ConsolClient END AS [Client]
If you need the row data, then select that into a variable and do a separate SELECT?
DECLARE #FinalClient int
SELECT #FinalClient = CASE
WHEN #MasterExpiry IS NULL AND #ConsolExpiry IS NULL THEN #MasterClient
WHEN #MasterExpiry IS NULL THEN #MasterClient
WHEN #ConsolExpiry IS NULL THEN #ConsolClient
WHEN #MasterExpiry >= #ConsolExpiry THEN #MasterClient
ELSE #ConsolClient END
SELECT * FROM #ProductSub WHERE ClientID = #FinalClient

Related

SQL Update Or Insert By Comparing Dates

I am trying to do the UPDATE or INSERT, but I am not sure if this is possible without using loop. Here is the example:
Says, I have this SQL below in which I joined two tables: tblCompany and tblOrders.
SELECT CompanyID, CompanyName, c.LastSaleDate, o.SalesOrderID, o.SalesPrice
, DATEADD(m, -6, GETDATE()) AS DateLast6MonthFromToday
FROM dbo.tblCompany c
CROSS APPLY (
SELECT TOP 1 SalesOrderID, SalesPrice
FROM dbo.tblOrders o
WHERE c.CompanyID = o.CompanyID
ORDER BY SalesOrderID DESC
) AS a
WHERE Type = 'End-User'
Sample Result:
CompanyID, SalesOrderID, SalesPrice, LastSalesDate, DateLast6MonthFromToday
101 10001 50 2/01/2016 10/20/2016
102 10002 80 12/01/2016 10/20/2016
103 10003 80 5/01/2016 10/20/2016
What I am trying to do is comparing the LastSalesDate and the DateLast6MonthFromToday. Condition is below:
If the LastSalesDate is lesser (earlier), then do the INSERT INTO tblOrders (CompanyID, Column1, Column2...) VALUES (CompanyIDFromQuery, Column1Value, Column2Value)
Else, do UPDATE tblOrders SET SalesPrice = 1111 WHERE SalesOrderID = a.SalesOrderID
As the above sample result, the query will only update SalesOrderID 10001 and 10003. And For Company 102, NO insert since the LastSaleDate is greater, then just do the UPDATE for the SalesOrderID.
I know it is probably can be done if I create a Cursor to loop through every record and do the comparison then Update or Insert, but I wonder if there is another way perform this without the loop since I have around 20K records.
Sorry for the confusion,
I don't know your tables structure and your data types. Also I know nothing
about duplicates and join ralationships between this 2 tables.
But I want only show how it works on next example:
use [your test db];
go
create table dbo.tblCompany
(
companyid int,
companyname varchar(max),
lastsaledate datetime,
[type] varchar(max)
);
create table dbo.tblOrders
(
CompanyID int,
SalesOrderID int,
SalesPrice float
);
insert into dbo.tblCompany
values
(1, 'Avito', '2016-01-01', 'End-User'),
(2, 'BMW', '2016-05-01', 'End-User'),
(3, 'PornHub', '2017-01-01', 'End-User')
insert into dbo.tblOrders
values
(1, 1, 500),
(1, 2, 700),
(1, 3, 900),
(2, 1, 500),
(2, 2, 700),
(2, 3, 900),
(3, 1, 500),
(3, 2, 700),
(3, 3, 900)
declare #column_1_value int = 5;
declare #column_2_value int = 777;
with cte as (
select
CompanyID,
SalesOrderID,
SalesPrice
from (
select
CompanyID,
SalesOrderID,
SalesPrice,
row_number() over(partition by CompanyID order by SalesOrderId desc) as rn
from
dbo.tblOrders
) t
where rn = 1
)
merge cte as target
using (select * from dbo.tblCompany where [type] = 'End-User') as source
on target.companyid = source.companyid
and source.lastsaledate >= dateadd(month, -6, getdate())
when matched
then update set target.salesprice = 1111
when not matched
then insert (
CompanyID,
SalesOrderID,
SalesPrice
)
values (
source.CompanyId,
#column_1_value,
#column_2_value
);
select * from dbo.tblOrders
If you will give me an information, then I can prepare target and source tables properly.

How to get the ID from the table which is not mention EndDate

How to get the name from the table which is not having EndDate
in the above pic i need to get D and G details from the table ,
( To understand mOre:
A, C,D,G are having end date, and A, C are again started, but D and G is not started, so from the query i need to get the name D and G
the code i used is not works for it
DECLARE #T AS TABLE
(
SubInventoryID int ,
SubInventoryName varchar(20),
RolesName varchar(20),
StartDate date,
EndDate date
)
INSERT INTO #T VALUES
(30,'RIF-Teller','Teller', '2016-12-27', '2017-01-23'),
(30,'RIF-Teller','Teller', '2016-12-08', NULL),
(30,'RIF-Teller','Teller', '2017-01-02', '2017-01-05'),
(31,'RIF-Teller','Teller', '2017-01-05', NULL),
(24,'MHQ-Teller','Teller', '2016-09-20', '2017-01-23'),
(24,'MHQ-Teller','Teller', '2016-08-01', '2017-01-05'),
(24,'MHQ-Teller','Teller', '2017-01-05', NULL)
Query
SELECT UP.SubInventoryID,S.SubInventoryName SubInventoryName,RolesName,UP.StartDate StartDate,
UP.EndDate EndDate , case when UP.EndDate IS null then 'Occupied' else 'Closed' End As Vacancy
FROM [View_Alx_UserPosition] UP
Inner join ALX_Branches B ON B.BranchID= UP.BranchID
Inner join ALX_SubInventories S ON S.SubInventoryID=UP.SubInventoryID WHERE UP.RolesName Like '%Teller%'
union
SELECT distinct(UP.SubInventoryID),S.SubInventoryName SubInventoryName, '' FullName, '' RolesName,NUll StartDate,
NUll EndDate,'Free' as vacancy
FROM [View_Alx_UserPosition] UP
Inner join ALX_Branches B ON B.BranchID= UP.BranchID
Inner join ALX_SubInventories S ON S.SubInventoryID=UP.SubInventoryID
WHERE UP.EndDate IS NOT NULL ANd UP.RolesName Like '%Teller%'
AND NOT EXISTS
(
SELECT 1
FROM [View_Alx_UserPosition] UP1
WHERE UP1.SubInventoryID = UP.SubInventoryID
AND UP1.StartDate >= UP.EndDate
-- AND UP1.EndDate IS NOT NULL
)
Update
Create and populate sample table (Please save us this step in your future questions)
DECLARE #T AS TABLE
(
ID int identity(1,1),
Name char(1),
StartDate date,
EndDate date
)
INSERT INTO #T VALUES
('A', '2016-04-04', '2017-04-03'),
('B', '2016-04-04', NULL),
('C', '2016-04-04', '2017-04-03'),
('D', '2016-04-04', '2017-04-03'),
('E', '2016-04-04', NULL),
('F', '2016-04-04', NULL),
('G', '2016-04-04', '2017-04-03'),
('C', '2017-04-03', NULL),
('A', '2017-04-03', NULL)
The query:
SELECT Name
FROM #T vu1
WHERE EndDate IS NOT NULL
AND NOT EXISTS
(
SELECT 1
FROM #T vu2
WHERE vu2.Name = vu1.Name
AND vu2.StartDate >= vu1.EndDate
)
Results:
Name
D
G
First version
Assuming I understand the question, this should do the trick:
SELECT Name
FROM View_User vu1
WHERE EndDate IS NOT NULL
AND NOT EXISTS
(
SELECT 1
FROM View_User vu2
WHERE vu2.Name = vu1.Name
AND vu2.StartDate >= vu1.EndDate
AND vu2.EndDate IS NOT NULL
)

SQL update one single row table with data from another

I have two tables. The first one with all movements in twelve months and the second one with claims registered in the same period of time. When I run the following query from the first table I've got 10 records. Of course, there are other records with a different number of movements (e.g.: 7, 23, 2 movements):
select t.cod_suc
,t.cod_ramo_comercial
,t.Poliza
,t.Item
,t.id_pv
from temp_portafolio_personal_accidents as t
where t.cod_suc = 2
and t.cod_ramo_comercial = 46
and t.Poliza = 50283
and t.Item = 1
and t.id_pv = 788383;
With the second query, for the second table, I have the following results:
select c.cod_suc
,c.cod_ramo_comercial
,c.[No. Policy]
,c.Item
,c.[ID Incident]
,max(c.id_pv) as id_pv
,count(distinct [No. Incident]) as 'Conteo R12'
from #claims as c
where c.[ID Incident] = 343632
group by c.cod_suc
,c.cod_ramo_comercial
,c.[No. Policy]
,c.Item
,c.[ID Incident];
Now, I need to update the first table but only one record. I'm using the following query, but all records are being updated. When I sum results I have 10 but is just one claim, as the second query shows.
update p
set [No. Siniestros R12] = b.[Conteo R12]
from temp_portafolio_personal_accidents p
left join
(select c.cod_suc
,c.cod_ramo_comercial
,c.[No. Policy]
,c.Item
,c.[ID Incident]
,max(c.id_pv) as id_pv
,count(distinct [No. Incident]) as 'Conteo R12'
from
#claims as c
where c.[ID Incident] = 343632
group by c.cod_suc
,c.cod_ramo_comercial
,c.[No. Policy]
,c.Item
,c.[ID Incident]
) b
on p.id_pv = b.id_pv
and p.cod_suc = b.cod_suc
and p.cod_ramo_comercial = b.cod_ramo_comercial
and p.Poliza = b.[No. Policy]
and p.Item = b.Item
where p.id_pv = 788383;
You can use a CTE with a ROW_NUMBER() function to do this. Simple example:
DECLARE #TABLE AS TABLE (Testing INT, Testing2 VARCHAR(55), Testing3 BIT);
INSERT INTO #TABLE VALUES (1, '1', 1);
INSERT INTO #TABLE VALUES (1, '1', 1);
INSERT INTO #TABLE VALUES (1, '1', 1);
INSERT INTO #TABLE VALUES (1, '1', 1);
INSERT INTO #TABLE VALUES (1, '1', 1);
INSERT INTO #TABLE VALUES (1, '1', 1);
INSERT INTO #TABLE VALUES (1, '1', 1);
INSERT INTO #TABLE VALUES (1, '1', 1);
WITH CTE AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY Testing) AS RowID
,Testing
,Testing2
,Testing3
FROM #TABLE
)
UPDATE CTE
SET Testing = 2, Testing2 = '2', Testing3 = 0
WHERE RowID = 1
;
SELECT * FROM #TABLE
;

SQL return only distinct IDs from LEFT JOIN

I've inherited some fun SQL and am trying to figure out how to how to eliminate rows with duplicate IDs. Our indexes are stored in a somewhat columnar format and then we pivot all the rows into one with the values as different columns.
The below sample returns three rows of unique data, but the IDs are duplicated. I need just two rows with unique IDs (and the other columns that go along with it). I know I'll be losing some data, but I just need one matching row per ID to the query (first, top, oldest, newest, whatever).
I've tried using DISTINCT, GROUP BY, and ROW_NUMBER, but I keep getting the syntax wrong, or using them in the wrong place.
I'm also open to rewriting the query completely in a way that is reusable as I currently have to generate this on the fly (cardtypes and cardindexes are user defined) and would love to be able to create a stored procedure. Thanks in advance!
declare #cardtypes table ([ID] int, [Name] nvarchar(50))
declare #cards table ([ID] int, [CardTypeID] int, [Name] nvarchar(50))
declare #cardindexes table ([ID] int, [CardID] int, [IndexType] int, [StringVal] nvarchar(255), [DateVal] datetime)
INSERT INTO #cardtypes VALUES (1, 'Funny Cards')
INSERT INTO #cardtypes VALUES (2, 'Sad Cards')
INSERT INTO #cards VALUES (1, 1, 'Bunnies')
INSERT INTO #cards VALUES (2, 1, 'Dogs')
INSERT INTO #cards VALUES (3, 1, 'Cat')
INSERT INTO #cards VALUES (4, 1, 'Cat2')
INSERT INTO #cardindexes VALUES (1, 1, 1, 'Bunnies', null)
INSERT INTO #cardindexes VALUES (2, 1, 1, 'playing', null)
INSERT INTO #cardindexes VALUES (3, 1, 2, null, '2014-09-21')
INSERT INTO #cardindexes VALUES (4, 2, 1, 'Dogs', null)
INSERT INTO #cardindexes VALUES (5, 2, 1, 'playing', null)
INSERT INTO #cardindexes VALUES (6, 2, 1, 'poker', null)
INSERT INTO #cardindexes VALUES (7, 2, 2, null, '2014-09-22')
SELECT TOP(100)
[ID] = c.[ID],
[Name] = c.[Name],
[Keyword] = [colKeyword].[StringVal],
[DateAdded] = [colDateAdded].[DateVal]
FROM #cards AS c
LEFT JOIN #cardindexes AS [colKeyword] ON [colKeyword].[CardID] = c.ID AND [colKeyword].[IndexType] = 1
LEFT JOIN #cardindexes AS [colDateAdded] ON [colDateAdded].[CardID] = c.ID AND [colDateAdded].[IndexType] = 2
WHERE [colKeyword].[StringVal] LIKE 'p%' AND c.[CardTypeID] = 1
ORDER BY [DateAdded]
Edit:
While both solutions are valid, I ended up using the MAX() solution from #popovitsj as it was easier to implement. The issue of data coming from multiple rows doesn't really factor in for me as all rows are essentially part of the same record. I will most likely use both solutions depending on my needs.
Here's my updated query (as it didn't quite match the answer):
SELECT TOP(100)
[ID] = c.[ID],
[Name] = MAX(c.[Name]),
[Keyword] = MAX([colKeyword].[StringVal]),
[DateAdded] = MAX([colDateAdded].[DateVal])
FROM #cards AS c
LEFT JOIN #cardindexes AS [colKeyword] ON [colKeyword].[CardID] = c.ID AND [colKeyword].[IndexType] = 1
LEFT JOIN #cardindexes AS [colDateAdded] ON [colDateAdded].[CardID] = c.ID AND [colDateAdded].[IndexType] = 2
WHERE [colKeyword].[StringVal] LIKE 'p%' AND c.[CardTypeID] = 1
GROUP BY c.ID
ORDER BY [DateAdded]
You could use MAX or MIN to 'decide' on what to display for the other columns in the rows that are duplicate.
SELECT ID, MAX(Name), MAX(Keyword), MAX(DateAdded)
(...)
GROUP BY ID;
using row number windowed function along with a CTE will do this pretty well. For example:
;With preResult AS (
SELECT TOP(100)
[ID] = c.[ID],
[Name] = c.[Name],
[Keyword] = [colKeyword].[StringVal],
[DateAdded] = [colDateAdded].[DateVal],
ROW_NUMBER()OVER(PARTITION BY c.ID ORDER BY [colDateAdded].[DateVal]) rn
FROM #cards AS c
LEFT JOIN #cardindexes AS [colKeyword] ON [colKeyword].[CardID] = c.ID AND [colKeyword].[IndexType] = 1
LEFT JOIN #cardindexes AS [colDateAdded] ON [colDateAdded].[CardID] = c.ID AND [colDateAdded].[IndexType] = 2
WHERE [colKeyword].[StringVal] LIKE 'p%' AND c.[CardTypeID] = 1
ORDER BY [DateAdded]
)
SELECT * from preResult WHERE rn = 1

How do I write this crosstab type query in Linq (tables & data provided)

This is a simple sort of crosstab query. I am having difficulty transferring my SQL knowledge to Linq and because it is hard to test (I have not gotten linqpad running properly for WP7 development) I can't really "play" easily.
CREATE TABLE Store
(
StoreID INT NOT NULL,
StoreName VARCHAR(10) NOT NULL
)
INSERT INTO Store (StoreID,StoreName) VALUES (1,'Store A')
INSERT INTO Store (StoreID,StoreName) VALUES (2,'Store B')
CREATE TABLE ProductType
(
ProductTypeID INT NOT NULL,
ProductTypeName VARCHAR(20) NOT NULL
)
INSERT INTO ProductType (ProductTypeID,ProductTypeName) VALUES (1,'Clothing')
INSERT INTO ProductType (ProductTypeID,ProductTypeName) VALUES (2,'Food')
CREATE TABLE Product
(
ProductID INT NOT NULL,
ProductTypeID INT NOT NULL,
ProductName VARCHAR(20) NOT NULL
)
INSERT INTO Product (ProductID,ProductTypeID,ProductName) VALUES (1,1,'Hat')
INSERT INTO Product (ProductID,ProductTypeID,ProductName) VALUES (2,1,'Shirt')
INSERT INTO Product (ProductID,ProductTypeID,ProductName) VALUES (3,1,'Pant')
INSERT INTO Product (ProductID,ProductTypeID,ProductName) VALUES (4,2,'Orange')
INSERT INTO Product (ProductID,ProductTypeID,ProductName) VALUES (5,2,'Apple')
CREATE TABLE Purchase
(
PurchaseID INT NOT NULL,
ProductID INT NOT NULL,
StoreID INT NOT NULL,
Quantity INT NULL,
Amount INT NULL
)
INSERT INTO Purchase (PurchaseID,ProductID,StoreID,Quantity,Amount) VALUES (1,1,1,5,10)
INSERT INTO Purchase (PurchaseID,ProductID,StoreID,Quantity,Amount) VALUES (2,2,1,4,12)
INSERT INTO Purchase (PurchaseID,ProductID,StoreID,Quantity,Amount) VALUES (3,3,1,1,10)
INSERT INTO Purchase (PurchaseID,ProductID,StoreID,Quantity,Amount) VALUES (4,4,1,3,16)
INSERT INTO Purchase (PurchaseID,ProductID,StoreID,Quantity,Amount) VALUES (5,5,1,7,12)
INSERT INTO Purchase (PurchaseID,ProductID,StoreID,Quantity,Amount) VALUES (6,1,2,10,22)
INSERT INTO Purchase (PurchaseID,ProductID,StoreID,Quantity,Amount) VALUES (7,2,2,8,26)
SELECT s.StoreName
,SUM(CASE
WHEN t.ProductTypeID=1 THEN Amount
ELSE 0
END ) as ClothingAmount
,SUM(CASE
WHEN t.ProductTypeID=2 THEN Amount
ELSE 0
END )AS FoodQuantity
,SUM(CASE
WHEN t.ProductTypeID=1 THEN Quantity
ELSE 0
END ) as ClothingAmount
,SUM(CASE
WHEN t.ProductTypeID=2 THEN Quantity
ELSE 0
END )AS FoodQuantity
FROM Purchase u
INNER JOIN Product r
ON u.ProductID=r.ProductID
INNER JOIN ProductType t
ON r.ProductTypeID=t.ProductTypeID
INNER JOIN Store s
ON s.StoreID=u.StoreID
GROUP BY s.StoreName
The following is a 1:1 translation of your SQL query statement in LINQ:
from u in Purchases
join r in Products on u.ProductID equals r.ProductID
join t in ProductTypes on r.ProductTypeID equals t.ProductTypeID
join s in Stores on u.StoreID equals s.StoreID
group new {Purchase = u, Product = r, ProductType = t, Store = s} by s.StoreName into grouped
select new {
StoreName = grouped.Key,
ClothingAmount = grouped.Sum(entry => entry.ProductType.ProductTypeID == 1 ? entry.Purchase.Amount : 0),
FoodAmount = grouped.Sum(entry => entry.ProductType.ProductTypeID == 2 ? entry.Purchase.Amount : 0),
ClothingQuantity = grouped.Sum(entry => entry.ProductType.ProductTypeID == 1 ? entry.Purchase.Quantity : 0),
FoodQuantity = grouped.Sum(entry => entry.ProductType.ProductTypeID == 2 ? entry.Purchase.Quantity : 0)
}
which gets translated into the following SQL:
SELECT SUM(
(CASE
WHEN [t2].[ProductTypeID] = #p0 THEN [t0].[Amount]
ELSE #p1
END)) AS [ClothingAmount], SUM(
(CASE
WHEN [t2].[ProductTypeID] = #p2 THEN [t0].[Amount]
ELSE #p3
END)) AS [FoodAmount], SUM(
(CASE
WHEN [t2].[ProductTypeID] = #p4 THEN [t0].[Quantity]
ELSE #p5
END)) AS [ClothingQuantity], SUM(
(CASE
WHEN [t2].[ProductTypeID] = #p6 THEN [t0].[Quantity]
ELSE #p7
END)) AS [FoodQuantity], [t3].[StoreName]
FROM [Purchase] AS [t0]
INNER JOIN [Product] AS [t1] ON [t0].[ProductID] = [t1].[ProductID]
INNER JOIN [ProductType] AS [t2] ON [t1].[ProductTypeID] = [t2].[ProductTypeID]
INNER JOIN [Store] AS [t3] ON [t0].[StoreID] = [t3].[StoreID]
GROUP BY [t3].[StoreName]
Note however that it is highly recommended to set proper primary and foreign keys on the tables. Once that's done (and the Model is updated accordingly) the same query can be reduced to:
from purchase in Purchases
group purchase by purchase.Store.StoreName into grouped
select new {
StoreName = grouped.Key,
ClothingAmount = grouped.Sum(purchase => purchase.Product.ProductTypeID == 1 ? purchase.Amount : 0),
FoodAmount = grouped.Sum(purchase => purchase.Product.ProductTypeID == 2 ? purchase.Amount : 0),
ClothingQuantity = grouped.Sum(purchase => purchase.Product.ProductTypeID == 1 ? purchase.Quantity : 0),
FoodQuantity = grouped.Sum(purchase => purchase.Product.ProductTypeID == 2 ? purchase.Quantity : 0)
}