problem with join SQL Server 2000 - sql-server

I have 3 tables -
Items,
Props,
Items_To_Props
i need to return all items that match all properties that i send
example
items
1
2
3
4
props
T1
T2
T3
items_to_props
1 T1
1 T2
1 T3
2 T1
3 T1
when i send T1,T2 i need to get only item 1

SELECT T.itemId
FROM (SELECT itemId, count(distinct prop) propCount
FROM items_to_props
WHERE prop in ('T1', 'T2')
GROUP BY itemId) T
WHERE T.propCount = 2
If you don't know how many props you have, you can create a temp table #P(prop), populate it with your props and run the folowing query (will do the same thing):
SELECT T.itemId
FROM (SELECT i.itemId, count(distinct p.prop) propCount
FROM items_to_props i
JOIN #P p on i.prop = p.prop
GROUP BY i.itemId) T
WHERE T.propCount = (SELECT COUNT(DISTINCT prop) FROM #P)

It is correct that you only get one row for T2, you should get 3 for T1

Related

Create a stored procedure to aggregate rows

Having a transaction table with the following rows:
Id UserId PlatformId TransactionTypeId
-------------------------------------------------
0 1 3 1
1 1 1 2
2 2 3 2
3 3 2 1
4 2 3 1
How do I write a stored procedure that can aggregate the rows into a new table with the following format?
Id UserId Platforms TransactionTypeId
-------------------------------------------------
0 1 {"p3":1,"p1":1} {"t1":1,"t2":1}
1 2 {"p3":2} {"t2":1,"t1":1}
3 3 {"p2":1} {"t1":1}
So the rows are gouped by User, count each platform/transactionType and store as key/value json string.
Ref: My previous related question
You could use GROUP BY and FOR JSON:
SELECT MIN(ID) AS ID, UserId, MIN(sub.x) AS Platforms, MIN(sub2.x) AS Transactions
FROM tab t
OUTER APPLY (SELECT CONCAT('p', platformId) AS platform, cnt
FROM (SELECT PlatformId, COUNT(*) AS cnt
FROM tab t2 WHERE t2.UserId = t.UserId
GROUP BY PlatformId) s
FOR JSON AUTO) sub(x)
OUTER APPLY (SELECT CONCAT('t', TransactiontypeId) AS Transactions, cnt
FROM (SELECT TransactiontypeId, COUNT(*) AS cnt
FROM tab t2 WHERE t2.UserId = t.UserId
GROUP BY TransactiontypeId) s
FOR JSON AUTO) sub2(x)
GROUP BY UserId;
DBFiddle Demo
Result is a bit different(array of key-value) but please treat it as starting point.
Your sample JSON is not really a json, but since you want it that way:
SELECT u.UserId, plt.pValue, ttyp.ttValue
FROM Users AS [u]
CROSS APPLY (
SELECT '{'+STUFF( (SELECT ',"'+pn.pName+'":'+LTRIM(STR(pn.pCount))
FROM (SELECT p.Name AS pName, COUNT(*) AS pCount
FROM transactions t
left JOIN Platforms p ON p.PlatformID = t.PlatformId
WHERE t.UserId = u.UserId
GROUP BY p.PlatformId, p.Name
) pn
FOR XML PATH('')),1,1,'')+'}'
) plt(pValue)
CROSS APPLY (
SELECT '{'+STUFF( (SELECT ',"'+tty.ttName+'":'+LTRIM(STR(tty.ttCount))
FROM (SELECT tt.Name AS ttName, COUNT(*) AS ttCount
FROM transactions t
left JOIN dbo.TransactionType tt ON tt.TransactionTypeId = t.TransactionTypeID
WHERE t.UserId = u.UserId
GROUP BY tt.TransactionTypeId, tt.Name
) tty
FOR XML PATH('')),1,1,'')+'}'
) ttyp(ttValue)
WHERE EXISTS (SELECT * FROM transactions t WHERE u.UserId = t.UserId)
ORDER BY UserId;
DBFiddle Sample

Joining Tables with Criteria

How do I create an MSSQL query that joins TableA with TableB using the ID field, however I want it to join on ID record that has the highest value in the Number column?
TableA
ID
1
2
3
4
TableB
ID Number
1 1
1 2
1 3
2 1
3 1
3 2
4 1
4 2
4 3
I would want this as my output
TableJoined
ID Number
1 3
2 1
3 2
4 3
Is there a way to use a LEFT JOIN to achieve this or using max()?
Both. Use aggregation on the left join.
Select t1.id, max(t2.number)
From table1 t1
Left join table2 t2 on t1.id= t2.id
Group by t1.id;
You can query as below:
Select a.Id, Number from #a a join
(
Select top(1) with ties * from #b
order by row_number() over(partition by id order by number desc)
) b on a.id = b.id
Select A.Id, Max(Number) MaxNo from A
join B on A.Id=B.Id
Group by A.Id
create table #a(
id int
)
go
create table #b(
id int,
number int
)
go
insert into #a values(1),(2),(3),(4)
insert into #b values(1,1),(1,2),(1,3),(2,1),(3,1),(3,2),(4,1),(4,2),(4,3)
select #b.id,MAX(number) as maximum
from #b left outer join #a on #b.id=#a.id
group by #b.id

TSQL Sum a value based on a double ID value

Here is a small simplified snipped of my data
OrderID QTY ItemID ActualQTY(does not exist in database)
1 2 1
2 1 2
3 1 1
4 5 3
Now I need a query that will fill in the ActualQTY based on the ItemID's. So summing total QTY for ItemID 1 = 3, and for ItemID 2 = 1, and last for ItemID 3 = 5
It should look like this
OrderID QTY ItemID ActualQTY
1 2 1 3
2 1 2 1
3 1 1 3
4 5 3 5
The problem is I am new to TSQL and I can't figure out a good way to do this.
--EDIT--
Someone else helped me with this problem and gave this solution which seems like the most efficient solution to me. However this solution doesn't work if you need to apply them to an XSD file in visual studio. So I turned it into a table valued function on the server.
SELECT OrderID, QTY, ItemID, SUM(QTY) OVER(PARTITION BY ItemID) AS ActualQTY
So if this solution doesn't work resort to answers below
You can do this:
SELECT
t2.OrderID,
t2.QTY,
t2.ItemID,
t1.ActualQTY
FROM
(
SELECT
ItemId,
SUM(QTY) AS ActualQTY
FROM tablename AS t1
GROUP BY ItemId
) AS t1
INNER JOIN tablename AS t2 ON t1.ItemId = t2.ItemID;
SQL Fiddle Demo
But if you want to update the column ActualQTY values, not just select, you can do this:
UPDATE t1
SET t1.ActualQTY = t2.ActualQTY
FROM tablename AS t1
INNER JOIN
(
SELECT
ItemId,
SUM(QTY) AS ActualQTY
FROM tablename AS t1
GROUP BY ItemId
) AS t2 ON t1.ItemID = t2.ItemID
SQL Fiddle Demo
SELECT b.OrderID,
b.QTY,
b.ItemID,
a.total_sum AS ActualQTY
FROM (SELECT ItemID,
Sum(QTY) AS total_sum
FROM tablename
GROUP BY ItemID) AS a
INNER JOIN tablename b
ON a.ItemID = b.ItemID
Select t.orderid, t.qty, t.itemid, a.actualq as actualqty
From yourtable t join (
Select sum(qty) as actualq, itemid
From yourtable
Group by itemid) a
On t.itemid = a.itemid

Using Joins to get all data from left table

I have two tables as shown below.
Id Name Id Status
-------- -------------------
1 A 1 Approved
2 B 6 Approved
3 C 4 Pending
4 D 1 Approved
5 E 1 Pending
6 F 3 Pending
5 Rejected
Now this is how I want the output to be:
Id Name Status
-------------------
1 A Pending
2 B
3 C Pending
4 D Pending
5 E
6 F
I have tried using left join but I am getting multiple rows.
select t1.ID,Name,Status from t1 left join t2 on t1.id=t2.id
and if I add where Status=pending i am getting only ids 1 and 3.
Here are the queries i tried:
select distinct t1.id,name,status from t1 left join t2 on t1.id=t2.id (this gives me duplicate records i.e id 1 is occurs twice with approved and pending)
and also
select distinct t1.id,name,status from t1 left join t2 on t1.id=t2.id where t2.status='pending' (gives me only 1,3 and 4)
Could any one help me,
Thanks in advance.
To include all rows from T1 and only those from T2 with status = 'pending' move the condition into the ON clause SQL Fiddle
SELECT t1.ID,
Name,
Status
FROM t1
LEFT JOIN t2
ON t1.id = t2.id
AND t2.status = 'pending'
To only return one row per id in the event of dupes you could do (Fiddle)
WITH CTE AS
(
SELECT DISTINCT id, Status
FROM T2
WHERE Status = 'Approved'
)
SELECT t1.ID,
Name,
Status
FROM t1
LEFT JOIN CTE
ON t1.id = CTE.id

inner join and group by

I have two tables with identical definition.
T1:
Name VARCHAR(50)
Qty INT
T2:
Name VARCHAR(50)
Qty INT
This is the data each table has:
T1:
Name Qty
a 1
b 2
c 3
d 4
T2:
Name Qty
a 1
b 3
e 5
f 10
I want to have result which can sum the Qty from both the tables based on Name.
Expected resultset:
Name TotalQty
a 2
b 5
c 3
d 4
e 5
f 10
If am do Left Join or Right Join, it is not going to return me the Name from either of the tables.
What i am thinking is to create a temp table and add these records and just do a SUM aggregate on Qty column but i think there should be a better way to do this.
This is how my query looks like which does not return the expected resultset:
SELECT t1.Name, ISNULL(SUM(t1.Qty + t2.Qty),0) TotalQty
FROM t1
LEFT JOIN t2
ON t1.Name = T2.Name
GROUP BY t1.Name
Can someone please tell me if creating a temp table is OK here or there is a better way to do this?
You can use a full outer join:
SELECT
ISNULL(t1.Name, t2.Name) AS Name,
ISNULL(t1.Qty, 0) + ISNULL(t2.Qty, 0) AS TotalQty
FROM t1
FULL JOIN t2 ON t1.Name = T2.Name
See it working online: sqlfiddle
You can use a UNION ALL to select both tables as one, since they have the same definition. From there, you can nest them as a derived table, and then SUM on that:
SELECT [Name], SUM(Qty) AS TotalQty
FROM (
SELECT [Name], Qty
FROM t1
UNION ALL
SELECT [Name], Qty
FROM t2
) YourDerivedTable
GROUP BY [Name]

Resources