TSQL join to another table with Group By - tsql

The pseudo code of what I currently have is
Cost + CostTax = CostActual
However, I need it to be:
Cost + tax - totalSumDiscounts = CostActual
I have a SQL Select statement at joins 3 tables that calculates cost + tax = CostActual.
SELECT dbo.XMP_EventUsers.ID, dbo.XMP_EventUsers.EventID, dbo.XMP_EventUsers.UserID,
CONVERT(VARCHAR(20),dbo.XMP_EventUsers.DateCreated, 100)
AS DateCreated, CONVERT(VARCHAR, dbo.XMP_Event.Cost, 1) AS Cost, dbo.Users.FirstName, dbo.Users.LastName,
dbo.XMP_Event.Cost + dbo.XMP_Event.CostTax - dbo.XMP_EventUsers.Paid AS Outstanding,
dbo.XMP_Event.Cost + dbo.XMP_Event.CostTax AS CostActual
FROM dbo.XMP_Event INNER JOIN
dbo.XMP_EventUsers ON dbo.XMP_Event.ID = dbo.XMP_EventUsers.EventID INNER JOIN
dbo.Users ON dbo.XMP_EventUsers.UserID = dbo.Users.UserID
Another table records discounts to be applied to the total cost. This query totals up the discounts to be applied.
SELECT UserID, SUM([Amount]) AS Amount
FROM [dbo].[XMP_EventPromoUsers]
GROUP BY UserID
How do I join the 2nd results to the first so that the total number of discount is minuses from the final cost in the select statement for each record?
Thanks for your help!
-R
Example results below for answer 1
Query 1 returns:
ID|EventID|UserID|DateCreated|Cost|FirstName|LastName|Outstanding|CostActual|FinalValue|
51|14-----|41----|Aug 11 2011|0.00|John-----|Smith---|-120-------|0.00------|-10-------|
Query 2
UserID-|Amount----|
41-----|10--------|
96-----|30--------|

SELECT
dbo.XMP_EventUsers.ID, dbo.XMP_EventUsers.EventID, dbo.XMP_EventUsers.UserID,
CONVERT(VARCHAR(20),dbo.XMP_EventUsers.DateCreated, 100) AS DateCreated,
CONVERT(VARCHAR, dbo.XMP_Event.Cost, 1) AS Cost,
dbo.Users.FirstName, dbo.Users.LastName,
dbo.XMP_Event.Cost + dbo.XMP_Event.CostTax - dbo.XMP_EventUsers.Paid AS Outstanding,
dbo.XMP_Event.Cost + dbo.XMP_Event.CostTax AS CostActual,
dbo.XMP_Event.cost + dbo.XMP_Event.CostTax - Users2.Amount AS FinalValue
FROM
dbo.XMP_Event
INNER JOIN dbo.XMP_EventUsers
ON dbo.XMP_Event.ID = dbo.XMP_EventUsers.EventID
INNER JOIN dbo.Users
ON dbo.XMP_EventUsers.UserID = dbo.Users.UserID
INNER JOIN (SELECT UserID, SUM([Amount]) AS Amount
FROM [dbo].[XMP_EventPromoUsers]
GROUP BY UserID) Users2
ON dbo.Users.UserID = Users2.UserID

Related

How to add sum to recursive query

I have this query
the table flights also contains price column. I'd like to sum it all up and display. How can I solve this?
Can I do this by taking the values from SELECT * from get_cities; somehow or it should be done in the query?
Table img
I am trying to solve this
Write a query finding all the names of the cities City name can be reached by plane with 3 stops. Display all the cities where the stop took place and the total cost of the trip. Also sum up the journey cost.
WITH RECURSIVE get_cities AS (
SELECT 0 as count, city, cid from cities where CITY = 'Agat'
UNION ALL
SELECT c.count + 1, b.city, b.cid from get_cities c
JOIN flights t on t.departure = c.cid
JOIN cities b on t.arrival = b.cid
WHERE COUNT < 3
)
SELECT cid, sum(price) from get_cities
JOIN flights f on f.fid = cid
GROUP BY cid
;
You can sum the prices directly in the recursive cte :
WITH RECURSIVE get_cities AS (
SELECT 0 as count, array[city] as city_path, array[cid] as cid_path, 0 as total_price
FROM cities
WHERE CITY = 'Agat'
UNION ALL
SELECT c.count + 1, c.city_path || b.city, c.cid_path || b.cid, c.total_price + t.price
FROM get_cities c
JOIN flights t on t.departure = c.cid
JOIN cities b on t.arrival = b.cid
WHERE COUNT < 3
)
SELECT *
FROM get_cities
WHERE count = 2 -- select only the journey with 3 stops ;

How to query two tables with same schema but different time ranges in a date column

I have two tables:
main_products
old_products
They have the same info and schema with only one difference:
main_products has min(date) = 2022-01 and max(date) = 2022-05
and
old_products has min(date) = 2020-01 and max(date) = 2020-12
How can I query to get all records from old_products + all records from main_products to get products from 2020-01 to 2022-05 ?
The product on both tables has and product_id field.
I tried to join both tables on product_id but the output is a table with twice number of columns.
select t1.*, t2.* from t1
inner join t2
one t1.product_id = t2.product_id
I think you are looking for a UNION or UNION ALL:
SELECT *
FROM t1
WHERE ...
UNION ALL
SELECT *
FROM t2
WHERE ...
If the columns in t1 and t2 are the same (same number of columns and same types), this will pull the data from both of them. Use UNION if you want duplicates removed or UNION ALL to include duplicates. (In your case it won't make a functional difference since the tables don't overlap by date, but UNION ALL will be faster.)
In the above example, you can put your condition (to only get 2022-01 to 2022-05) in both WHERE conditions. If you don't like repeating the condition, you can use the UNION ALL query in a subquery with the condition outside:
SELECT *
FROM
(
SELECT *
FROM t1
UNION ALL
SELECT *
FROM t2
) sq
WHERE ...

How to filter database table by a multiple join records from another one table but different types?

I have a products table and corresponding ratings table which contains a foreign key product_id, grade(int) and type which is an enum accepting values robustness and price_quality_ratio
The grades accept values from 1 to 10. So for example, how would the query look like, if I wanted to filter the products where minimum grade for robustness would be 7 and minimum grade for price_quality_ratio would be 8?
You can join twice, once per rating. The inner joins eliminate the products that fail any rating criteria,
select p.*
from products p
inner join rating r1
on r1.product_id = p.product_id
and r1.type = 'robustness'
and r1.rating >= 7
inner join rating r2
on r2.product_id = p.product_id
and r2.type = 'price_quality_ratio'
and r2.rating >= 8
Another option is to use do conditional aggregation. This requires only one join, then a group by; the rating criteria are checked in the having clause.
select p.product_id, p.product_name
from products p
inner join rating r
on r.product_id = p.product_id
and r.type in ('robustness', 'price_quality_ratio')
group by p.product_id, p.product_name
having
min(case when r.type = 'robustness' then r.rating end) >= 7
and min(case when r.type = 'price_quality_ratio then r.rating end) >= 8
The JOIN proposed by #GMB would've been my first suggestion as well. If that gets too complicated with having to maintain too many rX.ratings, you can also use a nested query:
SELECT *
FROM (
SELECT p.*, r1.rating as robustness, r2.rating as price_quality_ratio
FROM products p
JOIN rating r1 ON (r1.product_id = p.product_id AND r1.type = 'robustness')
JOIN rating r2 ON (r2.product_id = p.product_id AND r2.type = 'price_quality_ratio')
) AS tmp
WHERE robustness >= 7
AND price_quality_ratio >= 8
-- ORDER BY (price_quality_ratio DESC, robustness DESC) -- etc

SQL long execution time

This query works fine there is only one problem and that's his long execution time. Can someone show me some good optimizations and explain them.
SELECT TOP 5 PC.PersonID, P.FirstName, P.LastName, P.A, COUNT(*) Together
FROM PersonCheckIn PC
INNER JOIN Person P ON P.PersonID = PC.PersonID
WHERE CAST(CheckInDate AS DATE) IN (SELECT CAST(CheckInDate AS DATE)
FROM PersonCheckIn C
WHERE C.PersonId = 20) AND
PC.TimeTableID IN (SELECT CIn.TimeTableID
FROM PersonCheckIn CIn
WHERE CIn.PersonId = 20)
AND PC.PersonId <> 20 -- not count same person
GROUP BY PC.PersonId, P.FirstName, P.LastName, P.A
ORDER BY Together DESC;
Avoiding sub-queries and IN() Statement will drasticaly decrease execution time...
Even so CheckInDate is not prefixed with its table alias in your query (And we have to guess witch table is concerned :( ), maybe this will do the job :
SELECT TOP 5 PC.PersonID, P.FirstName, P.LastName, P.A, COUNT(*) Together
FROM PersonCheckIn PC
INNER JOIN Person P ON P.PersonID = PC.PersonID
INNER JOIN PersonCheckIn LU ON (LU.PersonId = 20 AND PC.CheckInDate = LU.CheckInDate AND PC.TimeTableID = LU.TimeTableID)
WHERE PC.PersonId <> 20 -- not count same person
GROUP BY PC.PersonId, P.FirstName, P.LastName, P.A
ORDER BY Together DESC;
If not, please :
- set the missing alias.
- give use data structure.
- give us data exemple.
- give us expected result exemple.

How do I join two tables with different column in SQL Server CE?

How can I joining two tables with different column in SQL Server CE?
I have two tables:
Table Schedule
+-----+----------+------+
+ ID + Name + Type +
+-----+----------+------+
+ 1 + A + 1 +
+ 2 + B + 1 +
+ 3 + C + 2 +
+-----+----------+------+
Table Description
+-----+--------------------+
+ ID + Description +
+-----+--------------------+
+ 1 + A1 - XXXXX +
+-----+--------------------+
And what I want to get is the table like:
+-----+----------+-----------------+
+ ID + Name + Description +
+-----+----------+-----------------+
+ 1 + A + A1 - XXXXX +
+ 2 + B + - +
+ 3 + C + - +
+-----+----------+-----------------+
Where the Description column should be filled in by - when the ID is not on the Description table.
I tried this code:
SELECT S.ID, D.Description
FROM Schedule AS S
INNER JOIN Description AS D
But resulted in:
+-----+----------+-----------------+
+ ID + Name + Description +
+-----+----------+-----------------+
+ 1 + A + A1 - XXXXX +
+ 2 + B + A1 - XXXXX +
+ 3 + C + A1 - XXXXX +
+-----+----------+-----------------+
And when I tried to give ON Clause:
SELECT S.ID, D.Description
FROM Schedule AS S
INNER JOIN Description AS D ON S.ID = D.ID
It just get the row where the ID is on the Description table, like:
+-----+----------+-----------------+
+ ID + Name + Description +
+-----+----------+-----------------+
+ 1 + A + A1 - XXXXX +
+-----+----------+-----------------+
How can I do that?
[UPDATE]
I tried this code and it works:
SELECT S.ID, S.Name, COALESCE (D.Description, '-') AS Description
FROM Schedule AS S
LEFT OUTER JOIN Description AS D ON S.ID = D.ID
But now, how can I add a WHERE clause on it (pls see table SCHEDULE above)?
I tried:
SELECT S.ID, S.Name, COALESCE (D.Description, '-') AS Description
FROM Schedule AS S
LEFT OUTER JOIN Description AS D ON S.ID = D.ID AND S.Type = '1'
But still get the whole rows.
LEFT OUTER JOIN in SQL Server CE
You need to use LEFT OUTER JOIN to join the tables Schedule and Description on the key field ID. Also, use COALESCE to replace NULL values in Description column with -
Script:
SELECT S.ID
, S.Name
, COALESCE (D.Description, '-') AS Description
FROM Schedule AS S
LEFT OUTER JOIN Description AS D
ON S.ID = D.ID
Output:
Tested in Microsoft SQL Server CE version 4.0.8482.1
With WHERE clause
You need add the WHERE clause after the JOINs. If you are planning to having an ORDER BY, it should come after the WHERE clause.
Script:
SELECT S.ID
, S.Name
, COALESCE (D.Description, '-') AS Description
FROM Schedule AS S
LEFT OUTER JOIN Description AS D
ON S.ID = D.ID
WHERE (S.Type = 1)
Output:
Tested in Microsoft SQL Server CE version 4.0.8482.1
You need LEFT OUTER JOIN.
SQLFiddle: http://sqlfiddle.com/#!3/7dccf/1
Query:
select s.ID, s.Name, Coalesce(d.description,'-') as description
from schedule s
left outer join description d on d.id = s.id
SELECT S.ID, D.Description
FROM Schedule AS S FULL OUTER JOIN Description AS D
ON S.ID = D.ID
INNER JOIN means select only rows that exist in both tables.
FULL OUTER JOIN means select rows as long as they exist in one table.
You need FULL OUTER JOIN...
You need to use an OUTER JOIN instead of INNER, and use IsNull or Coalesce to replace NULL values:
SELECT S.ID, Coalesce(D.Description , '-') AS Description
FROM Schedule AS S FULL OUTER JOIN Description AS D
ON S.ID = D.ID