SQL tournament date generator - sql

I am trying to create a tournament where in each team will play each other once both home and away.
I want to generate a date so that each Friday the teams will play one another
TempExampletable shows what the end result will look like with each team playing once per week.
TempExampletable2 shows the data I currently have and what I will be using to generate the date.
DROP TABLE TempExampletable;
DROP TABLE TempExampletable2;
CREATE TABLE TempExampletable(
Home VARCHAR(100),
Away VARCHAR (100),
Playing DATETIME
)
INSERT INTO TempExampletable VALUES
('Team 1', 'Team 2', '2017/12/01 17:30:00'),
('Team 1', 'Team 3', '2017/12/08 17:30:00'),
('Team 1', 'Team 4', '2017/12/15 17:30:00'),
('Team 2', 'Team 1', '2017/12/22 17:30:00'),
('Team 2', 'Team 3', '2017/12/15 17:30:00'),
('Team 2', 'Team 4', '2017/12/08 17:30:00'),
('Team 3', 'Team 1', '2017/12/29 17:30:00'),
('Team 3', 'Team 2', '2018/11/05 17:30:00'),
('Team 3', 'Team 4', '2017/12/01 17:30:00'),
('Team 4', 'Team 1', '2018/01/05 17:30:00'),
('Team 4', 'Team 2', '2017/12/29 17:30:00'),
('Team 4', 'Team 3', '2017/12/22 17:30:00')
CREATE TABLE TempExampletable2(
Home VARCHAR(100),
Away VARCHAR (100),
Playing DATETIME
)
INSERT INTO TempExampletable2(Home, Away) VALUES
('Team 1', 'Team 2'),
('Team 1', 'Team 3'),
('Team 1', 'Team 4'),
('Team 2', 'Team 1'),
('Team 2', 'Team 3'),
('Team 2', 'Team 4'),
('Team 3', 'Team 1'),
('Team 3', 'Team 2'),
('Team 3', 'Team 4'),
('Team 4', 'Team 1'),
('Team 4', 'Team 2'),
('Team 4', 'Team 3')
SELECT * FROM TempExampletable2 ORDER BY Playing ASC;
SELECT * FROM TempExampletable ORDER BY Playing ASC;

Here is a solution. Please format the date as you like or you can insert into a datetime column
WITH teams AS
(SELECT Home, Away,
row_number() over(order by Home, Away) - 1 AS r_num
FROM TempExampletable2 )
SELECT Home, Away, DATEADD(week, r_num, '2017/12/01 17:30:00') AS Playing
FROM teams
ORDER BY Playing ASC;
Output
Home Away Playing
Team 1 Team 2 2017-12-01T17:30:00Z
Team 1 Team 3 2017-12-08T17:30:00Z
Team 1 Team 4 2017-12-15T17:30:00Z
Team 2 Team 1 2017-12-22T17:30:00Z
Team 2 Team 3 2017-12-29T17:30:00Z
Team 2 Team 4 2018-01-05T17:30:00Z
Team 3 Team 1 2018-01-12T17:30:00Z
Team 3 Team 2 2018-01-19T17:30:00Z
Team 3 Team 4 2018-01-26T17:30:00Z
Team 4 Team 1 2018-02-02T17:30:00Z
Team 4 Team 2 2018-02-09T17:30:00Z
Team 4 Team 3 2018-02-16T17:30:00Z

You know that because there are 4 teams involved, there are 2 matchups per week. If, within a given week, you schedule one matchup you know the second matchup cannot involve either of the participants from the first. (Team 1 can't play Team 2 and Team 3 at the same time, regardless of Home/Away decisions) This scenario makes it difficult to handle this in a set based approach where you'd be making use of Recursive CTE's or other methods.
The above is why I have written a double nested while loop to schedule the tournament season. The first loop for going week by week, and the second scheduling a matchup in each iteration.
Sample Data:
I simplified the sample data down to a list of the teams, and later create the matchups shown in your TempExampletable2
create table #team_table
(
Team char(6) not null
)
insert into #team_table
values ('Team 1')
, ('Team 2')
, ('Team 3')
, ('Team 4')
Answer:
create table #matchups
(
Home char(6) not null
, Away char(6) not null
)
create table #schedule
(
Home char(6) not null
, Away char(6) not null
, Playing datetime not null
)
insert into #matchups
select h.Team as Home
, a.Team as Away
from #team_table as h
cross join #team_table as a
where 1=1
and h.Team <> a.Team
declare #bgn_dt datetime = '2017-12-01 17:30:00'
, #tm_cnt int = (select count(*) from #team_table)
, #i int = 1
, #j int
, #j_max int
, #wk_cnt int
, #rnd int
, #cur_dt datetime;
set #wk_cnt = ((#tm_cnt * (#tm_cnt - 1)) / 2)
set #j_max = (#tm_cnt / 2) --games in a week
while #i <= #wk_cnt
begin --while i
set #cur_dt = dateadd(d, 7 * (#i - 1), #bgn_dt)
set #j = 1
while #j <= #j_max
begin
; with sched_teams as
(
select s.Home as Team
from #schedule as s
where 1=1
and s.Playing = #cur_dt
union all
select s.Away as Team
from #schedule as s
where 1=1
and s.Playing = #cur_dt
)
insert into #schedule
select top 1 m.Home
, m.Away
, #cur_dt as Playing
from #matchups as m
left join sched_teams as sh on m.Home = sh.Team --same team can't play 2 games in a single week
left join sched_teams as sa on m.Away = sa.Team --same team can't play 2 games in a single week
left join #schedule as s on m.Home = s.Home --can't play the same matchup twice
and m.Away = s.Away
where 1=1
and sh.Team is Null
and sa.Team is Null
and s.Home is Null
and s.Away is Null
order by m.Home asc
, m.Away asc
set #j += 1
end
set #i += 1
end --while i
select *
from #schedule
order by Home
, Away
The order by on the insert...select statement is only there to force the output to be the same as the expected output specified in TempExampletable.

Related

Cant read count(*) value in temporary table

I want to fill a temporary table with values from another table and a count value, but it always throws the error:
Column name or number of supplied values does not match table
definition
My code looks like this:
CREATE TABLE #TempTable
([ObjectId] uniqueidentifier, [ListName] nvarchar(255), [HowMany] int)
INSERT INTO #TempTable
SELECT [ObjectId]
,[ListName]
,(SELECT COUNT(*) FROM [ATable] as a WHERE [ObjectId] = a.FK_ObjectId ) AS [HowMany]
FROM [AnotherTable]
It works fine for the other columns but not for the [HowMany] column.
I already tried to cast the SELECT count(*) to an integer but that also did not work.
What am I doing wrong?
I'm checking your request, I think that query below will help you, take a look please, I didn't use a temp table but is just the update the table names to be able to use a temp table.
As you didn't show us the structure of your table, I also made an example to make it simpler to understand, I think :-).
DECLARE #Category as table (
id int,
category nvarchar(50)
);
DECLARE #Product as table (
id int,
idCategory int,
productName nvarchar(50)
);
INSERT INTO #Category
VALUES
(1, 'Category 1'),
(2, 'Category 2'),
(3, 'Category 3')
INSERT INTO #Product
VALUES
(1,1, 'Product 1'),
(2,1, 'Product 2'),
(3,1, 'Product 3'),
(4,2, 'Product 4'),
(5,2, 'Product 5'),
(6,2, 'Product 6'),
(7,2, 'Product 7'),
(8,2, 'Product 8'),
(9,3, 'Product 9'),
(10,3, 'Product 10'),
(11,3, 'Product 11'),
(12,3, 'Product 12')
--To know how many product is used by category
SELECT * FROM
(
SELECT
C.*,
(Count(P.id) over (partition by C.ID order by C.category)) as HowManyProductByCategory
FROM
#Category as C
INNER JOIN #Product as P ON C.id = P.idCategory
) as T
GROUP BY T.id, T.category, T.HowManyProductByCategory
The result
id category HowManyProductByCategory
1 Category 1 3
2 Category 2 5
3 Category 3 4
Best Regards

Select rows which does not have sum equals to zero

I have two tables: #temptable_1 and #temptable_2. I need to select rows which do not have rows in another table that can be subtracted. Let me clarify:
Row with column "Code" with "Code 1" has a "Price" that has value "-2000". Row with column "Code 4" has a "Price" that has value "2000".
It means that if we sum this columns, then the Sum will be zero. So these both rows
should not be selected.
Row with column "Code" with "Code 2" has a "Amount" that has value "-10780.56". Row with column "Code 5" has a "Amount" that has value "10780.56".
It means that if we sum this columns, then the Sum will be zero. So these both rows
should not be selected.
Row with column "Code" with "Code 3" has a "AmountIncVAT" that has value "-12936.67". Row with column "Code 6" has a "AmountIncVAT" that has value "12936.67". It means that if we sum this columns, then the Sum will be zero. So these both rows
should not be selected.
Row with column "Code" with "Code 7" should be in the select result because it cannot be summed with other columns of temptable_1
So, columns that can be summed are: Price, VAT, Amount, AmountIncVAT
Tables looks like this:
DROP TABLE IF EXISTS #temptable_1
CREATE TABLE #temptable_1 ( [Name] varchar(10), [Code] varchar(50), [id_Car] int, [PositionName] varchar(1000),
[Count] decimal(18,3), [id_Unit] int, [Price] decimal(15,2), [VAT] decimal(15,2),
[Amount] decimal(15,2), [AmountIncVAT] decimal(15,2))
INSERT INTO #temptable_1
VALUES
( '1', 'Code 1', 632324, 'Position 1', 1.000, 1036, -2000.00, -401.00, 2001.00, 2401.00),
( '2', 'Code 2', 632324, 'Position 2', 1.000, 1036, -10780.56, -2156.11, -10780.56, 10.67),
( '3', 'Code 3', 632324, 'Position 3', 1.000, 1036, -18780.56, -1, 558.56, -12936.67)
DROP TABLE IF EXISTS #temptable_2
CREATE TABLE #temptable_2 ( [Name] varchar(10), [Code] varchar(50), [id_Car] int, [PositionName] varchar(1000),
[Count] decimal(18,3), [id_Unit] int, [Price] decimal(15,2), [VAT] decimal(15,2),
[Amount] decimal(15,2), [AmountIncVAT] decimal(15,2))
INSERT INTO #temptable_2
VALUES
( '4', 'Code 4', 632324, 'Position 4', 1.000, 1036, 2000.00, 402.00, 3001.00, 8101.00),
( '5', 'Code 5', 632324, 'Position 5', 1.000, 1036, 11780.56, 2156.11, 10780.56, 18936.67),
( '6', 'Code 6', 632324, 'Position 6', 1.000, 1036, 10580.56, 3, -21780.56, 12936.67),
( '7', 'Code 7', 632324, 'Position 7', 8.000, NULL, 415.34, 664.54, 3322.72, 3987.26)
The desired result is one row with "Code 7":
7 Code 6 632324 Position 6 8.000 NULL 415.34 664.54 3322.72 3987.26
I have written the following code:
SELECT
*
FROM
(
SELECT
COUNT(1) OVER (PARTITION BY ABS(q.Price) ORDER BY ABS(q.Price)) as CountByPrice
, COUNT(1) OVER (PARTITION BY ABS(q.Vat) ORDER BY ABS(q.Vat)) as CountByVat
, COUNT(1) OVER (PARTITION BY ABS(q.Amount) ORDER BY ABS(q.Amount)) as CountByAmount
, COUNT(1) OVER (PARTITION BY ABS(q.AmountIncVAT) ORDER BY ABS(q.AmountIncVAT)) as CountByAmountIncVat
, q.*
FROM
(
SELECT * FROM #temptable_1
UNION ALL
SELECT * FROM #temptable_2
) AS q
) AS q1
WHERE q1.CountByPrice =1 AND q1.CountByVat =1 AND q1.CountByAmount = 1 AND q1.CountByAmountIncVat = 1
Is it possible to write this code shorter?
WITH
-- your input
temptable_1(Name,Code,id_Car,PositionName,Count,id_Unit,Price,VAT,Amount,AmountIncVAT)
AS (
SELECT '1', 'Code 1', 632324, 'Position 1', 1.000, 1036, -2000.00, -401.00, 2001.00, 2401.00
UNION ALL SELECT '2', 'Code 2', 632324, 'Position 2', 1.000, 1036, -10780.56, -2156.11, -10780.56, 10.67
UNION ALL SELECT '3', 'Code 3', 632324, 'Position 3', 1.000, 1036, -18780.56, -1, 558.56, -12936.67
)
,
temptable_2 ( Name , Code , id_Car , PositionName , Count , id_Unit , Price , VAT , Amount , AmountIncVAT)
AS (
SELECT'4', 'Code 4', 632324, 'Position 4', 1.000, 1036, 2000.00, 402.00, 3001.00, 8101.00
UNION ALL SELECT'5', 'Code 5', 632324, 'Position 5', 1.000, 1036, 11780.56, 2156.11, 10780.56, 18936.67
UNION ALL SELECT'6', 'Code 6', 632324, 'Position 6', 1.000, 1036, 10580.56, 3, -21780.56, 12936.67
UNION ALL SELECT'7', 'Code 7', 632324, 'Position 7', 8.000, NULL, 415.34, 664.54, 3322.72, 3987.26
)
-- your input ends here. Real query starts here, replace comma with WITH
,
botht AS (
SELECT * FROM temptable_1
UNION ALL
SELECT * FROM temptable_2
)
SELECT
*
FROM botht b
WHERE NOT EXISTS(
SELECT 1 FROM botht c WHERE b.price = c.price * -1
)
AND NOT EXISTS(
SELECT 1 FROM botht c WHERE b.amount = c.amount * -1
)
AND NOT EXISTS(
SELECT 1 FROM botht c WHERE b.amountIncVAT = c.amountIncVAT * -1
)
;
-- out Name | Code | id_Car | PositionName | Count | id_Unit | Price | VAT | Amount | AmountIncVAT
-- out ------+--------+--------+--------------+-------+---------+--------+--------+---------+--------------
-- out 7 | Code 7 | 632324 | Position 7 | 8.000 | | 415.34 | 664.54 | 3322.72 | 3987.26

Sum of 2 columns if row exists in Table 2 - SQL

CREATE TABLE #Details
(
SName VARCHAR(20),
PName VARCHAR(20),
SoldCount INT,
Value INT
)
CREATE TABLE #DetailsException
(
ExSName VARCHAR(20),
ExPName VARCHAR(20)
)
INSERT INTO #Details(SName, PName, SoldCount,Value) VALUES ('Store 1', 'Product 1', 10,400)
INSERT INTO #Details(SName, PName, SoldCount,Value) VALUES ('Store 1', 'Product 3', 3,500)
INSERT INTO #Details(SName, PName, SoldCount,Value) VALUES ('Store 2', 'Product 1', 8,30)
INSERT INTO #Details(SName, PName, SoldCount,Value) VALUES ('Store 2', 'Product 2', 10,25)
INSERT INTO #Details(SName, PName, SoldCount,Value) VALUES ('Store 2', 'Product 2', 23,120)
INSERT INTO #Details(SName, PName, SoldCount,Value) VALUES ('Store 4', 'Product 1', 23,50)
INSERT INTO #Details(SName, PName, SoldCount,Value) VALUES ('Store 4', 'Product 3', 10,50)
INSERT INTO #Details(SName, PName, SoldCount,Value) VALUES ('Store 4', 'Product 5', 7,200)
INSERT INTO #Details(SName, PName, SoldCount,Value) VALUES ('Store 5', 'Product 1', 10,100)
INSERT INTO #Details(SName, PName, SoldCount,Value) VALUES ('Store 5', 'Product 1', 24,240)
INSERT INTO #DetailsException(ExSName, ExPName) VALUES ('Store 2', 'Product 2')
INSERT INTO #DetailsException(ExSName, ExPName) VALUES ('Store 4', 'Product 5')
SELECT SName, PName, **CASE WHEN EXISTS(SELECT 1 FROM #DetailsException WHERE ExSName = SName AND ExPName = PNAme ) THEN 0 ELSE SUM(SoldCount) END AS SoldCount**, SUM(Value) AS Value
FROM #Details
GROUP BY SNAME, PNAME
ORDER BY SNAME, PNAME
The result set is correct. Although I want to know if there any other optimized way of writing it in SQL. Since both the tables will grow extremely large in size.
Thanks.
I think I would be more inclined to write this as a LEFT JOIN:
SELECT d.SName, d.PName,
SUM(CASE WHEN de.ExSname IS NOT NULL THEN 0 ELSE SoldCount END) AS SoldCount,
SUM(Value) AS Value
FROM #Details d LEFT JOIN
#DetailsException de
ON de.ExSName = d.SName AND de.ExPName = d.PNAme
GROUP BY d.SNAME, d.PNAME
ORDER BY d.SNAME, d.PNAME;
However, your method is fine.
Considering the ExSName, ExPName is unique in
Here is another way using LEFT JOIN.
SELECT SName,
PName,
Sum(CASE
WHEN de.ExSName IS NULL THEN ( SoldCount )
ELSE 0
END) AS SoldCount,
Sum(Value) AS Value
FROM #Details d
LEFT JOIN (select distinct ExSName,ExPName from #DetailsException) de
ON de.ExSName = d.SName
AND de.ExPName = d.PNAme
GROUP BY SNAME,
PNAME
ORDER BY SNAME,
PNAME
Check the performance by running the queries. You can create Non-clustered index on SName,PNAme column to improve the performance
CREATE NONCLUSTERED INDEX IX_details_temp
ON #Details (SNAME, PNAME)
include (SoldCount, Value);
Added covering index (SoldCount, Value) to avoid Clustered/Heap lookup. Note, Index will be useful only if you are going to filter records from #details table. And for #DetailsException table creating the below index could be helpful
CREATE NONCLUSTERED INDEX IX_DetailsException_temp
ON #DetailsException (ExSName, ExPName)

Sort data in SQL Server based on parent child relation

I have a table where I store details about the chapters, I have to show data in following order of Table of Index
Chapter One
1.1 Chapter One Page 1
1.2 Chapter One Page 2
Chapter Two
2.1 Chapter Two Page 1
2.2 Chapter Two Page 2
Chapter Three
Title One
Title Two
Title Three
3.1 Chapter Three Page 1
3.2 Chapter Three Page 2
3.3 Chapter Three Page 3
We can insert data in database in sorted or un-sorted order. But data should show in a sorted order based on pageOrder of Parent and Child pages
I have set up SQL Fiddle but for some reason I am not able to save SQL. Below you will find fiddle link and details
CREATE TABLE [Book]
(
[id] int,
[Chapter] varchar(20),
[PageOrder] int,
[parentID] int
);
INSERT INTO [Book] ([id], [Chapter], [PageOrder], [parentID])
VALUES
('1', 'Chapter One', 1, 0),
('2', 'Chapter Two', 2, 0),
('3', 'Chapter Three', 3, 0),
('4', 'Chapter Four', 4, 0),
('5', 'Chapter Five', 5, 0),
('6', 'Chapter One Page 1', 1, 1),
('7', 'Chapter One Page 2', 2, 1),
('8', 'Chapter One Page 3', 3, 1),
('9', 'Chapter One Page 4', 4, 1),
('10', 'Chapter Two Page 1', 1, 2),
('11', 'Chapter Two Page 3', 3, 2),
('12', 'Chapter Two Page 2', 2, 2),
('13', 'Chapter Three Tite 1', 0, 3),
('14', 'Chapter Three Tite 2', 0, 3),
('15', 'Chapter Three Tite 3', 0, 3),
('16', 'Chapter Three Page 2', 2, 3),
('17', 'Chapter Three Page 3', 3, 3),
('18', 'Chapter Three Page 1', 1, 3);
WITH CTE(ID, parentID, Chapter, PageOrder, Depth, SortCol) AS
(
SELECT
ID, parentID, Chapter, PageOrder, 0,
CAST(ID AS varbinary(max))
FROM Book
WHERE parentID = 0
UNION ALL
SELECT
d.ID, d.parentID, d.Chapter, d.PageOrder, p.Depth + 1,
CAST(SortCol + CAST(d.ID AS binary(4)) AS varbinary(max))
FROM Book AS d
JOIN CTE AS p ON d.parentID = p.ID
)
SELECT
ID, parentID, Chapter, PageOrder, Depth,
REPLICATE('--', Depth) + Chapter as PageName
FROM CTE
ORDER BY SortCol
This CTE query is sorting data but it child pages are not properly sorted child pages show up in sort order in which they where saved in database
SqlFiddle Link http://www.sqlfiddle.com/#!3/9770a/1
The Complete Solution like
SELECT * FROM
(
SELECT p.CategoryID
, p.Category_Name
, p.IsParent
, p.ParentID
, p.Active
, p.Sort_Order AS Primary_Sort_Order
, CASE WHEN p.IsParent = 0 THEN (SELECT Sort_Order FROM tbl_Category WHERE
CategoryID = p.ParentID) ELSE p.Sort_Order END AS Secondary_Sort_Order
FROM tbl_Category p
) x
ORDER BY Secondary_Sort_Order,
CASE WHEN ParentID = 0 THEN CategoryID ELSE ParentID END,
CASE WHEN ParentID = 0 THEN 0 ELSE Primary_Sort_Order END,
Primary_Sort_Order ASC
Hope It helps....!
Use PageOrder instead of ID to build SortCol, also cast to VARCHAR(MAX) instead of VARBINARY(MAX):
WITH CTE(ID, parentID, Chapter, PageOrder, Depth, SortCol) AS (
SELECT ID, parentID, Chapter,PageOrder, 0,
CAST(PageOrder AS varchar(max))
FROM Book
WHERE parentID = 0
UNION ALL
SELECT d.ID, d.parentID, d.Chapter, d.PageOrder, p.Depth + 1,
CAST(SortCol + CAST(d.PageOrder AS varchar(max)) AS varchar(max))
FROM Book AS d
JOIN CTE AS p ON d.parentID = p.ID
)
SELECT ID, parentID, Chapter, PageOrder, Depth, SortCol,
REPLICATE('--', Depth) + Chapter as PageName
FROM CTE
ORDER BY SortCol, Chapter
Additionally Chapter column is used to sort chapters having the same PageOrder and belonging to the same tree level.
Demo here
SELECT *, REPLICATE('--', CASE WHEN parentID > 0 THEN 1 ELSE 0 END) + Chapter AS PageName
FROM Book
ORDER BY COALESCE(NULLIF(parentID,0), id), parentID, PageOrder

SQL Join by rolling date period

I am using an SQL Server 2005 database. In it I have an Audit table, and would like to know when a value was changed relative to a period. The period simply has a start date, and any Audit change after it should be displayed up until the next periods start date. If there is no next period start date, I would also like to display the result.
Here is the code to create the table and input data:
CREATE TABLE [dbo].[Period](
[Id] [int] NOT NULL,
[Name] [varchar](50) NOT NULL,
[StartDate] [datetime] NOT NULL
)
INSERT INTO [dbo].[Period] VALUES (1, 'Period 1', '2015-03-01')
INSERT INTO [dbo].[Period] VALUES (2, 'Period 2', '2015-04-01')
INSERT INTO [dbo].[Period] VALUES (3, 'Period 3', '2015-05-01')
CREATE TABLE [dbo].[Audit](
[Id] [int] NOT NULL,
[OldValue] [VARCHAR](50),
[NewValue] [VARCHAR](50),
[DateModified] [DATETIME] NOT NULL,
)
INSERT INTO [dbo].[Audit] VALUES (1, 'Old Value 1', 'New Value 1', '2015-03-27')
INSERT INTO [dbo].[Audit] VALUES (2, 'Old Value 2', 'New Value 2', '2015-04-03')
INSERT INTO [dbo].[Audit] VALUES (3, 'Old Value 3', 'New Value 3', '2015-04-09')
INSERT INTO [dbo].[Audit] VALUES (4, 'Old Value 4', 'New Value 4', '2015-05-12')
http://sqlfiddle.com/#!6/b012c
What I would like is to display the data as follows:
Period 1 | Old Value 1 | New Value 1
Period 2 | Old Value 2 | New Value 2
Period 2 | Old Value 3 | New Value 3
Period 3 | Old Value 4 | New Value 4
Can anyone explain what technique to use?
select
(select top 1 Name from Period where StartDate < DateModified order by StartDate desc),
a.OldValue,
a.NewValue
from Audit a
This should work for what you're after:
Select P.Name, A.OldValue, A.NewValue
From Period P
LEFT JOIN
Period P2 on P2.Id = P.Id + 1
INNER JOIN
Audit A on A.DateModified > P.StartDate and (A.DateModified < P2.StartDate or P2.StartDate is null)