Sum of 2 columns if row exists in Table 2 - SQL - 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)

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

Solving a Query on SQLDeveloper

need some help on solving this query.
I want to get projects that had no change in their team (i.e. because project0002 has two different project managers it must not appear on the result of the query)
Can you help me ?
CREATE TABLE sprintMembers (
userID NUMBER(10) NOT NULL,
sprintNumber NUMBER(10) NOT NULL,
sprintProjectCode VARCHAR(255) NOT NULL,
memberRole VARCHAR(255) NOT NULL,
PRIMARY KEY (userID, sprintNumber, sprintProjectCode));
INSERT INTO sprintMembers VALUES (4,1,'PROJ0001', 'Project Manager');
INSERT INTO sprintMembers VALUES (5,1,'PROJ0001', 'Product Owner');
INSERT INTO sprintMembers VALUES (6,1,'PROJ0001', 'Scrum Master');
INSERT INTO sprintMembers VALUES (4,1,'PROJ0002', 'Project Manager');
INSERT INTO sprintMembers VALUES (3,2,'PROJ0002', 'Project Manager');
INSERT INTO sprintMembers VALUES (4,3,'PROJ0002', 'Project Manager');
INSERT INTO sprintMembers VALUES (5,1,'PROJ0002', 'Product Owner');
INSERT INTO sprintMembers VALUES (5,2,'PROJ0002', 'Product Owner');
INSERT INTO sprintMembers VALUES (7,1,'PROJ0002', 'Team Member');
INSERT INTO sprintMembers VALUES (7,2,'PROJ0002', 'Team Member');
INSERT INTO sprintMembers VALUES (4,1,'PROJ0003', 'Project Manager');
INSERT INTO sprintMembers VALUES (4,2,'PROJ0003', 'Project Manager');
INSERT INTO sprintMembers VALUES (5,1,'PROJ0003', 'Product Owner');
INSERT INTO sprintMembers VALUES (5,2,'PROJ0003', 'Product Owner');
INSERT INTO sprintMembers VALUES (7,1,'PROJ0003', 'Scrum Master');
INSERT INTO sprintMembers VALUES (7,2,'PROJ0003', 'Scrum Master');
INSERT INTO sprintMembers VALUES (6,1,'PROJ0003', 'Team Member');
INSERT INTO sprintMembers VALUES (6,2,'PROJ0003', 'Team Member');
INSERT INTO sprintMembers VALUES (8,1,'PROJ0004', 'Project Manager');
INSERT INTO sprintMembers VALUES (8,2,'PROJ0004', 'Project Manager');
INSERT INTO sprintMembers VALUES (8,3,'PROJ0004', 'Project Manager');
INSERT INTO sprintMembers VALUES (9,1,'PROJ0004', 'Product Owner');
INSERT INTO sprintMembers VALUES (9,2,'PROJ0004', 'Product Owner');
INSERT INTO sprintMembers VALUES (9,3,'PROJ0004', 'Product Owner');
INSERT INTO sprintMembers VALUES (10,1,'PROJ0004', 'Scrum Master');
INSERT INTO sprintMembers VALUES (10,2,'PROJ0004', 'Scrum Master');
INSERT INTO sprintMembers VALUES (10,3,'PROJ0004', 'Scrum Master');
INSERT INTO sprintMembers VALUES (6,1,'PROJ0004', 'Team Member');
INSERT INTO sprintMembers VALUES (6,2,'PROJ0004', 'Team Member');
INSERT INTO sprintMembers VALUES (6,3,'PROJ0004', 'Team Member');
If I understand correctly you can aggregate and count distinct userId
select sprintProjectCode
from sprintMembers
group by sprintProjectCode
having Count(distinct case when memberRole='project manager' then userid end)=1
Result:
PROJ0001
PROJ0003
PROJ0004
Edit
Another approach applying to all member role values
with groups as (
select sprintProjectCode, Count(*) cnt
from sprintMembers
group by sprintProjectCode, userid, memberrole
)
select sprintProjectCode
from groups
group by sprintProjectCode
having Min(cnt) = Max(cnt)

SQL LEFT JOIN to many categories

Suppose the following easy scenario, where a product row gets connected to one primary category, subcategory, and sub-subcategory.
DECLARE #PRODUCTS TABLE (ID int, DESCRIPTION varchar(50), CAT varchar(30), SUBCAT varchar(30), SUBSUBCAT varchar(30));
INSERT #PRODUCTS (ID, DESCRIPTION, CAT, SUBCAT, SUBSUBCAT) VALUES
(1, 'NIKE MILLENIUM', '1', '10', '100'),
(2, 'NIKE CORTEZ', '1', '12', '104'),
(3, 'ADIDAS PANTS', '2', '27', '238'),
(4, 'PUMA REVOLUTION 5', '3', '35', '374'),
(5, 'SALOMON SHELTER CS', '4', '15', '135'),
(6, 'NIKE EBERNON LOW', '2', '14', '157');
DECLARE #CATS TABLE (ID int, DESCR varchar(100));
INSERT #CATS (ID, DESCR) VALUES
(1, 'MEN'),
(2, 'WOMEN'),
(3, 'UNISEX'),
(4, 'KIDS'),
(5, 'TEENS'),
(6, 'BACK TO SCHOOL');
DECLARE #SUBCATS TABLE (ID int, DESCR varchar(100));
INSERT #SUBCATS (ID, DESCR) VALUES
(10, 'FOOTWEAR'),
(12, 'OUTERWEAR'),
(14, 'SWIMWEAR'),
(15, 'HOODIES'),
(27, 'CLOTHING'),
(35, 'SPORTS');
DECLARE #SUBSUBCATS TABLE (ID int, DESCR varchar(100));
INSERT #SUBSUBCATS (ID, DESCR) VALUES
(100, 'RUNNING'),
(104, 'ZIP TOPS'),
(135, 'FLEECE'),
(157, 'BIKINIS'),
(238, 'PANTS'),
(374, 'JOGGERS');
SELECT prod.ID,
prod.DESCRIPTION,
CONCAT(cat1.DESCR, ' > ', cat2.DESCR, ' > ', cat3.DESCR) AS CATEGORIES
FROM #PRODUCTS AS prod
LEFT JOIN #CATS AS cat1 ON cat1.ID = prod.CAT
LEFT JOIN #SUBCATS AS cat2 ON cat2.ID = prod.SUBCAT
LEFT JOIN #SUBSUBCATS AS cat3 ON cat3.ID = prod.SUBSUBCAT;
Now suppose that the foreign keys on #PRODUCTS table aren't just indices to their respective tables. They are comma-separated indices to more than one categories, subcategories, and sub-subcategories like here.
DECLARE #PRODUCTS TABLE (ID int, DESCRIPTION varchar(50), CAT varchar(30), SUBCAT varchar(30), SUBSUBCAT varchar(30));
INSERT #PRODUCTS (ID, DESCRIPTION, CAT, SUBCAT, SUBSUBCAT) VALUES
(1, 'NIKE MILLENIUM', '1, 2', '10, 12', '100, 135'),
(2, 'NIKE CORTEZ', '1, 5', '12, 15', '104, 374'),
(3, 'ADIDAS PANTS', '2, 6', '27, 35', '238, 374');
DECLARE #CATS TABLE (ID int, DESCR varchar(100));
INSERT #CATS (ID, DESCR) VALUES
(1, 'MEN'),
(2, 'WOMEN'),
(3, 'UNISEX'),
(4, 'KIDS'),
(5, 'TEENS'),
(6, 'BACK TO SCHOOL');
DECLARE #SUBCATS TABLE (ID int, DESCR varchar(100));
INSERT #SUBCATS (ID, DESCR) VALUES
(10, 'FOOTWEAR'),
(12, 'OUTERWEAR'),
(14, 'SWIMWEAR'),
(15, 'HOODIES'),
(27, 'CLOTHING'),
(35, 'SPORTS');
DECLARE #SUBSUBCATS TABLE (ID int, DESCR varchar(100));
INSERT #SUBSUBCATS (ID, DESCR) VALUES
(100, 'RUNNING'),
(104, 'ZIP TOPS'),
(135, 'FLEECE'),
(157, 'BIKINIS'),
(238, 'PANTS'),
(374, 'JOGGERS');
SELECT prod.ID,
prod.DESCRIPTION
--CONCAT(cat1.DESCR, ' > ', cat2.DESCR, ' > ', cat3.DESCR) AS CATEGORIES
FROM #PRODUCTS AS prod
--LEFT JOIN #CATS AS cat1 ON cat1.ID = prod.CAT
--LEFT JOIN #SUBCATS AS cat2 ON cat2.ID = prod.SUBCAT
--LEFT JOIN #SUBSUBCATS AS cat3 ON cat3.ID = prod.SUBSUBCAT;
In this case I want to achieve the following:
Be able to retrieve the respective names of the cats, subcats, sub-subcats, ie. for cats '1, 2' be able to retrieve their names (I tried LEFT JOIN #CATS AS cat1 ON cat1.ID IN prod.CAT but it doesn't work)
Create triplets of the corresponding cats, subcats, sub-subcats, ie. for
cats '1, 2'
subcats '12, 17'
sub-subcats '239, 372'
(after retrieving the appropriate names) create pipe-separated category routes like name of cat 1 > name of subcat 12 > name of sub-subcat 239 | name of cat 2 > name of subcat 17 > name of sub-subcat 372
So, for a row like (1, 'NIKE MILLENIUM', '1, 2', '10, 12', '100, 135'),
I would like to get the following result
ID
DESCRIPTION
CATEGORIES
1
NIKE MILLENIUM
MEN > FOOTWEAR > RUNNING # WOMEN > OUTERWEAR > FLEECE (I had to use # as the delimiter of the two triplets because pipe messed with the table's columns)
In case the user stupidly stores more cat IDs than subcat IDs, or sub-subcat IDs, the query should just match the ones that have a corresponding position match, ie for
cats '1, 2'
subcats '12'
sub-subcats '239, 372'
it should just create one triplet, like name of 1 > name of 12 > name of 239
STRING_SPLIT() does not promise to return the values in a specific order, so it won't work in this case as ordinal position matters.
Use OPENJSON() split the string into separate rows to ensure the values are returned in the same order.
OPENJSON() also returns a key field, so you can join on the row number within each grouping. You'll want an INNER JOIN since your requirement is that all values in that "column" must exist.
Use STUFF() to assemble the various cat>subcat>subsubcat values.
DECLARE #PRODUCTS TABLE (ID int, DESCRIPTION varchar(50), CAT varchar(30), SUBCAT varchar(30), SUBSUBCAT varchar(30));
INSERT #PRODUCTS (ID, DESCRIPTION, CAT, SUBCAT, SUBSUBCAT) VALUES
(1, 'NIKE MILLENIUM', '1, 2', '10, 12', '100, 135'),
(2, 'NIKE CORTEZ', '1, 5', '12, 15', '104, 374'),
(3, 'ADIDAS PANTS', '2, 6, 1', '27, 35, 10', '238, 374, 100'),
(4, 'JOE THE PLUMBER JEANS', '1, 5', '27', '238, 374');
DECLARE #CATS TABLE (ID int, DESCR varchar(100));
INSERT #CATS (ID, DESCR) VALUES
(1, 'MEN'),
(2, 'WOMEN'),
(3, 'UNISEX'),
(4, 'KIDS'),
(5, 'TEENS'),
(6, 'BACK TO SCHOOL');
DECLARE #SUBCATS TABLE (ID int, DESCR varchar(100));
INSERT #SUBCATS (ID, DESCR) VALUES
(10, 'FOOTWEAR'),
(12, 'OUTERWEAR'),
(14, 'SWIMWEAR'),
(15, 'HOODIES'),
(27, 'CLOTHING'),
(35, 'SPORTS');
DECLARE #SUBSUBCATS TABLE (ID int, DESCR varchar(100));
INSERT #SUBSUBCATS (ID, DESCR) VALUES
(100, 'RUNNING'),
(104, 'ZIP TOPS'),
(135, 'FLEECE'),
(157, 'BIKINIS'),
(238, 'PANTS'),
(374, 'JOGGERS');
;
with prod as (
SELECT p.ID,
p.DESCRIPTION
--CONCAT(cat1.DESCR, ' > ', cat2.DESCR, ' > ', cat3.DESCR) AS CATEGORIES
, c.value as CatId
, c.[key] as CatKey
, sc.value as SubCatId
, sc.[key] as SubCatKey
, ssc.value as SubSubCatId
, ssc.[key] as SubSubCatKey
FROM #PRODUCTS p
cross apply OPENJSON(CONCAT('["', REPLACE(cat, ', ', '","'), '"]')) c
cross apply OPENJSON(CONCAT('["', REPLACE(subcat, ', ', '","'), '"]')) sc
cross apply OPENJSON(CONCAT('["', REPLACE(subsubcat, ', ', '","'), '"]')) ssc
where c.[key] = sc.[key]
and c.[key] = ssc.[key]
)
, a as (
select p.ID
, p.DESCRIPTION
, c.DESCR + ' > ' + sc.DESCR + ' > ' + ssc.DESCR as CATEGORIES
, p.CatKey
from prod p
inner join #CATS c on c.ID = p.CatId
inner join #SUBCATS sc on sc.ID = p.SubCatId
inner join #SUBSUBCATS ssc on ssc.ID = p.SubSubCatId
)
select DISTINCT ID
, DESCRIPTION
, replace(STUFF((SELECT distinct ' | ' + a2.CATEGORIES
from a a2
where a.ID = a2.ID
FOR XML PATH(''))
,1,2,''), '>', '>') CATEGORIES
from a
Totally separate answer because of the change to older technology. I think my original answer is still good for folks using current SQL Server versions, so I don't want to remove it.
I don't remember where I got the function. When I found it today it was named split_delimiter. I changed the name, added some comments, and incorporated the ability to have a delimiter that is more than one character long.
CREATE FUNCTION [dbo].[udf_split_string](#delimited_string VARCHAR(8000), #delimiter varchar(10))
RETURNS TABLE AS
RETURN
WITH cte10(num) AS ( -- 10 rows
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
, cte100(num) AS ( -- 100 rows
SELECT 1
FROM cte10 t1, cte10 t2
)
, cte10000(num) AS ( -- 10000 rows
SELECT 1
FROM cte100 t1, cte100 t2
)
, cte1(num) AS ( -- 1 row per character
SELECT TOP (ISNULL(DATALENGTH(#delimited_string), 0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM cte10000
)
, cte2(num) AS ( -- locations of strings
SELECT 1
UNION ALL
SELECT t.num + len(replace(#delimiter, ' ', '_'))
FROM cte1 t
WHERE SUBSTRING(#delimited_string, t.num, len(replace(#delimiter, ' ', '_'))) = #delimiter
)
, cte3(num, [len]) AS (
SELECT t.num
, ISNULL(NULLIF(CHARINDEX(#delimiter, #delimited_string, t.num), 0) - t.num, 8000)
FROM cte2 t
)
SELECT [Key] = ROW_NUMBER() OVER (ORDER BY t.num)
, [Value] = SUBSTRING(#delimited_string, t.num, t.[len])
FROM cte3 t;
GO
DECLARE #PRODUCTS TABLE (ID int, DESCRIPTION varchar(50), CAT varchar(30), SUBCAT varchar(30), SUBSUBCAT varchar(30));
INSERT #PRODUCTS (ID, DESCRIPTION, CAT, SUBCAT, SUBSUBCAT) VALUES
(1, 'NIKE MILLENIUM', '1, 2', '10, 12', '100, 135'),
(2, 'NIKE CORTEZ', '1, 5', '12, 15', '104, 374'),
(3, 'ADIDAS PANTS', '2, 6, 1', '27, 35, 10', '238, 374, 100'),
(4, 'JOE THE PLUMBER JEANS', '1, 5', '27', '238, 374');
DECLARE #CATS TABLE (ID int, DESCR varchar(100));
INSERT #CATS (ID, DESCR) VALUES
(1, 'MEN'),
(2, 'WOMEN'),
(3, 'UNISEX'),
(4, 'KIDS'),
(5, 'TEENS'),
(6, 'BACK TO SCHOOL');
DECLARE #SUBCATS TABLE (ID int, DESCR varchar(100));
INSERT #SUBCATS (ID, DESCR) VALUES
(10, 'FOOTWEAR'),
(12, 'OUTERWEAR'),
(14, 'SWIMWEAR'),
(15, 'HOODIES'),
(27, 'CLOTHING'),
(35, 'SPORTS');
DECLARE #SUBSUBCATS TABLE (ID int, DESCR varchar(100));
INSERT #SUBSUBCATS (ID, DESCR) VALUES
(100, 'RUNNING'),
(104, 'ZIP TOPS'),
(135, 'FLEECE'),
(157, 'BIKINIS'),
(238, 'PANTS'),
(374, 'JOGGERS');
;
with prod as (
SELECT p.ID,
p.DESCRIPTION
, c.value as CatId
, c.[key] as CatKey
, sc.value as SubCatId
, sc.[key] as SubCatKey
, ssc.value as SubSubCatId
, ssc.[key] as SubSubCatKey
FROM #PRODUCTS p
cross apply dbo.udf_split_string(cat, ', ') c
cross apply dbo.udf_split_string(subcat, ', ') sc
cross apply dbo.udf_split_string(subsubcat, ', ') ssc
where c.[key] = sc.[key]
and c.[key] = ssc.[key]
)
, a as (
select p.ID
, p.DESCRIPTION
, c.DESCR + ' > ' + sc.DESCR + ' > ' + ssc.DESCR as CATEGORIES
, p.CatKey
from prod p
inner join #CATS c on c.ID = p.CatId
inner join #SUBCATS sc on sc.ID = p.SubCatId
inner join #SUBSUBCATS ssc on ssc.ID = p.SubSubCatId
)
select DISTINCT ID
, DESCRIPTION
, replace(STUFF((SELECT distinct ' | ' + a2.CATEGORIES
from a a2
where a.ID = a2.ID
FOR XML PATH(''))
,1,2,''), '>', '>') CATEGORIES
from a
Well that should do work, i changed your character ">" for "-" just for see the data more simple.
the design of your tables is not perfect but the first try almost never is.
select mainp.ID, mainp.DESCRIPTION, stuff(ppaths.metapaths, len(ppaths.metapaths),1,'') metalinks
from #PRODUCTS mainp
cross apply(
select
(select
c.DESCR + '-' + sc.DESCR + '-' + sbc.DESCR + '|'
from #PRODUCTS p
cross apply (select row_number() over(order by Value) id, Value from split(p.CAT, ','))cat_ids
inner join #cats c on c.ID = cat_ids.Value
cross apply (select row_number() over(order by Value) id, Value from split(p.SUBCAT, ','))subcat_ids
inner join #SUBCATS sc on sc.ID = subcat_ids.Value
and subcat_ids.id = subcat_ids.id
cross apply (select row_number() over(order by Value) id, Value from split(p.SUBSUBCAT, ','))subsubcat_ids
inner join #SUBSUBCATS sbc on sbc.ID = subsubcat_ids.Value
and subsubcat_ids.id = subcat_ids.id
where p.id = mainp.ID
for xml path('')) metapaths
) ppaths
the link for split function
https://desarrolladores.me/2014/03/sql-server-funcion-split-para-dividir-un-string/

SQL tournament date generator

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.

Match name to ID and replace on insert

Imagine an insert that looks like this:
INSERT INTO Inventory VALUES ('Product Name 1', 'Inventoried Location', Count),
('Product Name 2', 'Inventoried Location', Count),
('Product Name 3', 'Inventoried Location', Count),
...
('Product Name 1000', 'Inventoried Location', Count),
('Product Name 1001', 'Inventoried Location', Count)
Is there a way to match the Product Name to its ID in a Products table and substitute the ID for the name on insert? Needs to work for thousands of entries on the insert.
Performance would be pretty awful on this, but if you're stuck with that particular format (say, from an Excel spreadsheet or something) you can write this as:
INSERT INTO Inventory VALUES
(SELECT ProductID FROM Product WHERE ProductName = 'Product Name 1', 'Inventoried Location', 5),
(SELECT ProductID FROM Product WHERE ProductName = 'Product Name 2', 'Inventoried Location', 5),
(SELECT ProductID FROM Product WHERE ProductName = 'Product Name 3', 'Inventoried Location', 5),
...
(SELECT ProductID FROM Product WHERE ProductName = 'Product Name 1000', 'Inventoried Location', 5),
(SELECT ProductID FROM Product WHERE ProductName = 'Product Name 1001', 'Inventoried Location', 5)
Of course, this will break if you have multiple product entries with the same ProductName ...
If you want some better performance, you could insert the values into a temporary table, then do the lookup from that in a similar way to how Siyual suggested, e.g.,
INSERT INTO #tmpInventory (ProductName, ProductLocation, Number) VALUES
('Product Name 1', 'Inventoried Location', 5),
('Product Name 2', 'Inventoried Location', 5),
('Product Name 3', 'Inventoried Location', 5),
.......
INSERT INTO INVENTORY (ProductID, ProductLocation, Number)
SELECT p.ProductID, t.ProductLocation, t.Number
FROM #tmpInventory t
INNER JOIN Product p on t.ProductName = p.ProductName
You can do something like this:
Insert Inventory
Select ProductId, 'Inventoried Location', 5
From Products
Where ProductName = 'Product Name'