Multiplying Count of Instances in SQL - sql-server

I have a data base that I need to query to count and sum the number of points generated by a pass from a player in a basketball game. For instance, if a player passes to a teammate and that pass results in 2 points, my data base currently stores that as 1 instance in certain table. There is another table that the data is stored in if the pass resulted in 3 points. I would like to query so that all instances of a pass from a player that results in 2 points are counted and then multiplied by 2, and all instances of a pass from a player that results in 3 points are counted and then multiplied by 3.
Here are my relevant tables and select statements:
CREATE TABLE Passer(
PasserID int identity PRIMARY KEY not null
, Forename char(30) not null
, Surname char (30) not null)
CREATE TABLE Teammate(
TeammateID int identity PRIMARY KEY not null
, Forename char(30) not null
, Surname char(30) not null
, PasserID int FOREIGN KEY REFERENCES Passer(PasserID) not null)
CREATE TABLE TwoPointsFromShot(
TwoPointsFromShotID int identity PRIMARY KEY not null
, PasserID int FOREIGN KEY REFERENCES Passer(PasserID) not null
, TeammateID int FOREIGN KEY REFERENCES Teammate(TeammateID) not null)
CREATE TABLE ThreePointsFromShot(
ThreePointsFromShotID int identity PRIMARY KEY not null
, PasserID int FOREIGN KEY REFERENCES Passer(PasserID) not null
, TeammateID int FOREIGN KEY REFERENCES Teammate(TeammateID) not null
--First and Last Name of Passer from TwoPointsFromShot--
SELECT Forename, Surname
FROM Passer
JOIN TwoPointsFromShot ON TwoPointsFromShot.PasserID = Passer.PasserID
--First And Last name of Passer from ThreePointsFromShot--
SELECT Forename, Surname
FROM Passer
JOIN ThreePointsFromShot ON ThreePointsFromShot.PasserID = Passer.PasserID
When I query the PasserID from the TwoPointsFromShot table, I receive a table that looks like:
| PasserID
------------------- | --------
1 | 1
2 | 3
3 | 3
4 | 2
I receive a similar table when querying PasserID from ThreePointsFromShot table.
| PasserID
--------------------- | --------
1 | 3
2 | 1
3 | 3
4 | 4
I would like to return a query that counts the number of instances of the PasserID from TwoPointsFromShot and multiplies that by 2, counts the number of instances of the PasserID from ThreePointsFromShot and multiples that by 3, sums the two values, and replaces the PasserID with the name of the player. So it would look like this (if Julius Randle is PlayerID 1, Dario Saric is PlayerID 2, TJ McConnell is PlayerID 3, and Brandon Ingram is PlayerID 4):
| PasserName | PointsFromTwo | PointsFromThree | PassToPoints
--- | --------- | --------------- | ------------------ | ------------
1 | Julius Randle | 2 | 3 | 5
2 | Dario Saric | 2 | 0 | 2
3 | TJ McConnell | 4 | 6 | 10
4 | Brandon Ingram| 0 | 3 | 3
Any help would be greatly appreciated!

I was able to get the results you want by using two common table expressions.
--CTE to get number of 2 pointers
WITH twoPointers AS
(
SELECT PasserId,COUNT(*) '2ptCount'
FROM TwoPointsFromShot
GROUP BY PasserID
),
--CTE to get number of 3 pointers
threePointers As
(
SELECT PasserId,COUNT(*) '3ptCount'
FROM ThreePointsFromShot
GROUP BY PasserID
)
--Join the Passer table with 2 CTE's and
--calculate results
SELECT RTRIM(Forename) + ' ' + RTRIM(Surname) AS 'PasserName',
ISNULL(two.[2ptCount] * 2, 0.00) AS 'PointsFromTwo',
ISNULL(three.[3ptCount] * 3, 0.00) AS 'PointsFromThree',
ISNULL(two.[2ptCount] * 2, 0.00) + ISNULL(three.[3ptCount] * 3, 0.00) AS 'PassToPoints'
FROM Passer p
LEFT JOIN twoPointers two ON p.PasserID = two.PasserID
LEFT JOIN threePointers three ON p.PasserID = three.PasserID

Related

Merging tables with unique ID

I have two temp tables.
Table 1 contains all the string info
ID | string1 | string2 | etc...
Table 2 contains of the int values
ID | int1 | int2 | etc...
They both share a unique ID.
I need to join them so that it first shows all the the info from table 1 and WHEN there is a matching ID in table 2 to add those values to the end of the table, otherwise when table 2 does not contain that ID to put in a 0, There is never a case when table 1 does not have the ID that is in Table 2
So when the ID is in table 2
ID | String1 | String2 | int1 | int2 |
AND when the ID is not in Table 2
ID | String1 | String2 | 0 | 0 |
When you need all rows from left table use LEFT JOIN and for controlling value of table2 use ISNULL function.
Select t1.ID, t1.string1, t1.string2, ISNULL(t2.int1, 0) int1, ISNULL(t2.int2, 0) int2
FROM [table 1] t1
LEFT JOIN [table 2] t2 ON t1.ID = t2.ID
Also it is not called merging tables, but joining.

Compare two data sets in TABLE A and insert into TABLE B

I have a scenario. There are two Tables TABLE-A and TABLE-B. The source is TABLE-A. The destination is TABLE-B. I want to compare the ID with self join. If ID is matching i want to ensure only NOT NULL value is picked. If both records has NULL value then Null value can be considered as ouput.
Below scenario,
TABLE-A has one duplicate ID i.e 1. In output i will be have one value for that duplicate record and merge data intelligently that NULL VALUES are excluded and if both records are having NULL for any column then NULL will be populated in TABLE-B.
TABLE A
ID NAME ADDRESS PHONE STATUS PROCESSFLAG
1 YOU XYZ NULL NULL 1
2 PQR ABC 123 Active 2
1 YOU NULL 322 NULL 2
OUTPUT TABLE B
ID NAME ADDRESS PHONE STATUS PROCESSFLAG
2 PQR ABC 123 Active 2
1 YOU XYZ 322 NULL 2
You can group by id and select max() for each column to exclude nulls:
insert into tableb(id, name, address, phone, status, processflag)
select id, max(name), max(address), max(phone), max(status), max(processflag)
from tablea
group by id
I assume that your problem is the nulls and the non null columns of the duplicates have the same value in different rows or you want the maximum of the 2 values like your sample data.
See the demo.
Results:
ID | NAME | ADDRESS | PHONE | STATUS | PROCESSFLAG
-: | :--- | :------ | :---- | :----- | ----------:
1 | YOU | XYZ | 322 | null | 2
2 | PQR | ABC | 123 | Active | 2

Left Outer Join Including Missing Rows from 2nd Table

I am having some difficulty in doing a LEFT OUTER JOIN in SQLite3 and have not been able to find the resolution in StackOverflow's existing documents, but that may be just a reflection of ....
Basically, the issue is that the second table does not have some matching rows and I want the result set to contain NULL values for those rows.
The Table Structures:
(a) tblITEMS with columns:
ID (integer, primary key, not null)
DESCR (Text); i.e., description
(b) tblVALUES with columns:
ID (integer, primary key, not null)
ITEM_ID (integer, not null, foreign key to tblITEMS.ID)
VAL_DT (not null); i.e., the valuation date
VALUE (real, not null, default 0)
The Data:
(a) tblITEMS has five (5) rows.
__ID__|_DESCR_|
:----:|:-----:|
1 | Item1 |
2 | Item2 |
3 | Item3 |
4 | Item4 |
5 | Item5 |
(b) tblVALUES has four (4) rows with
(bi) two rows have the same ITEM_ID, but different VAL_DTs
(bii) two rows have ITEM_IDs different from (bi).
(c) There are zero (0) rows that match two (2) of the tblITEM IDs.
__ID__|_ITEM_ID_|__VAL_DT_____|__VALUE__|
:----:|:-------:|:-----------:|:-------:|
1 | 1 | 2000-01-01 | 10 |
2 | 2 | 2000-01-01 | 20 |
3 | 2 | 2010-01-01 | 200 |
4 | 3 | 2000-01-01 | 40 |
The desired result set:
Five (5) rows, one for each tblITEMS row, which contains NULL entries for the tblVALUES columns that do not have a matching ITEM_ID; i.e. do not exist.
SQL script that gives three (3) rows, each of which has the appropriate values from the tblVALUES table.
select a.ID, a.DESCR, b.ID as VAL_ID, b.ITEM_ID, Date(b.Val_dt) as Val_dt, b.VALUE
from
tblItems a
, tblValues b
--left outer join tblValues on a.id = b.item_id
where
a.id = b.item_id
and
b.val_dt = (Select Max(b.val_dt) from tblValues b where (a.id = b.ITEM_ID))
order by a.id
Above SQL script with the "left outer join" line uncommented yeilds a result set with:
(a) Twelve (12) rows.
(b) Four (4) duplicates of each of three (3) unique rows (same as returned by 4. above). The unique rows all have appropriate values from tblVALUES.
(c) Zero (0) rows corresponding to the tblITEMS that do not have a corresponding row in the tblVALUES table.
THE QUESTION:
How should the SQL script be modified so that the result set contains five (5) rows, one for each tblITEMS row AND contains NULL values for the tblITEM rows that do not have a corresponding row in the tblVALUES table?
Expected / desired result set:
__ID__|_DESCR_|_ITEM_ID_|__VAL_DT_____|__VALUE__|
:----:|:-----:|:-------:|:-----------:|:-------:|
1 | Item1 | 1 | 2000-01-01 | 10 |
2 | Item2 | 2 | 2010-01-01 | 200 |
3 | Item3 | 3 | 2000-01-01 | 40 |
4 | Item4 | NULL | NULL | NULL |
5 | Item5 | NULL | NULL | NULL |
Note: NULLs may be zero or a "null date".
I'm answering my own question because I've solved the problem.
I am somewhat embarrassed by how simple the solution was.
In any case, my fundamental problem was that I did not fully understand that the "JOIN" clauses are actually part of the main "FROM" clause, which means that the table on the right side of the join and its alias definition should only appear in the join clause.
The actual solution is:
Select a.ID
, a.DESCR
, b.ID AS VALUES_ID
, b.ITEM_ID
, b.VAL_DT
, b.VALUE
FROM tblITEMS a
LEFT OUTER JOIN tblVALUES b ON a.ID = b.ITEM_ID
AND b.val_dt = (Select Max(b.val_dt)
From tblVALUES b
Where a.ID = b.ITEM_ID)
Order by
a.ID
Regards,
John

SQL Query to get data based on multiple filters

I have following Product table and ProductTag tables -
ID | Product
--------------
1 | Product_A
2 | Product_B
3 | Product_C
TagID | ProductID
----------------------
1 | 2
1 | 3
2 | 1
2 | 2
2 | 3
3 | 1
3 | 2
Now I need a SQL query that return all products list which are having both Tag 1 and 2. Result should be as given below -
ProductID | Product
------------------------
2 | Product_B
3 | Product_C
Please suggest how can i write a MS SQL query for this.
SELECT p.ID, p.Product
FROM Product p
INNER JOIN ProductTag pt
ON p.ID = pt.ProductID
WHERE pt.TagID IN (1, 2) -- <== Tags you want to find
GROUP BY p.ID, o.Product
HAVING COUNT(*) = 2 -- <== tag count on WHERE clause
however, if TagID is not unique on every Product, you need to count only the distinct product.
HAVING COUNT(DISTINCT pt.TagID) = 2
More on: SQL of Relational Division

Updating a set of data from the next matching record

I have a table that contains the status history (including current status) of a number of resources. It looks something like this:
CREATE TABLE [dbo].[RESOURCE_STATUS](
[id] [int] IDENTITY(1,1) NOT NULL,
[resource_id] [int] NOT NULL,
[date_timestamp] [datetime] NOT NULL,
[end_timestamp] [datetime] NULL,
...
)
And an example of the data ( obviously represents a valid timestamp):
+------+-------------+-----------------+---------------+
| id | resource_id | start_timestamp | end_timestamp |
+------+-------------+-----------------+---------------+
| 1 | 1 | <valid_ts> | <valid_ts> |
| 2 | 2 | <valid_ts> | <valid_ts> |
| 3 | 3 | <valid_ts> | NULL |
| 4 | 1 | <valid_ts> | NULL |
| 5 | 2 | <valid_ts> | NULL |
| 6 | 1 | <valid_ts> | <valid_ts> |
| 7 | 2 | <valid_ts> | NULL |
| 8 | 1 | <valid_ts> | NULL |
+------+-------------+-----------------+---------------+
There are, of course, additional columns representing the status etc but I don't think they are relevant at this point.
In theory, the start_timestamp and end_timestamp in each record are supposed to indicate the date and time of the start and end of each status with a NULL end_timestamp indicating that the status is ongoing (in this case rows 3, 7 and 8 indicate ongoing statuses).
The problem I have is that in some cases (rows 4 and 5 in the example) the end_timestamp hasn't been set and to get our reporting system working properly I need to go back and set that timestamp from the start_timestamp in the next record for that resource in the set if it exists. I.E. update row 4 from row 6 and row 5 from row 7. Rows 3, 7 and 8 shouldn't be modified since they represent the current state of the resource.
Note that the row missing the end_timestamp may not be the first row for that resource_id and there may be multiple rows for one or more resources that have incorrectly NULL end_timestamps.
I need to do this both for the existing data and on an ongoing basis when data is added to the table (I know the creator of the data should be fixed, but for various reasons that isn't on the table at this point).
In case it's relevant, we're using MS SQL Server 2008 and the table currently contains just over two million rows and obviously is growing on a daily basis.
Can anyone help me out with this please?
Try this...
WITH AddRowNumber AS
(
SELECT
id
, resource_id
, start_timestamp
, end_timestamp
, ROW_NUMBER() OVER(PARTITION BY resource_id ORDER BY start_timestamp) AS RowNumber
FROM
#Resource_Status
)
, NewTimestamp AS
(
SELECT
A1.id
, A1.resource_id
, A1.start_timestamp
, A1.end_timestamp
, A2.start_timestamp AS NewEndTimeStamp
FROM
AddRowNumber AS A1
INNER JOIN
AddRowNumber AS A2
ON
A1.resource_id = A2.resource_id
AND A1.RowNumber = A2.RowNumber - 1
WHERE
A1.end_timestamp IS NULL
)
UPDATE
#Resource_Status
SET
end_timestamp = Nt.NewEndTimeStamp
FROM
#Resource_Status AS R
INNER JOIN
NewTimestamp AS NT
ON
R.id = NT.id
Let me know if that works.
Ash

Resources