Matrix table SQL - sql

I have three tables:
Table tCity
(Id int, City nvarchar(50))
Table tLocation
(Id int, Location nvarchar(50))
Table tCityLocation
(Id int, CityId int, LocationId int)
I would like to generate matrix table like in image below.
If City belongs to location-> in appropriate cell in table, char X will be written down.
I would like to about any sophisticated approach how to reach it. I had issue in similar logic and processed by iteration in cursors with dynamically added column to result set table.
Exists any sophisticated approach instead of cursor and dynamically added column?
Thank you.

It should be something like this:
DECLARE #DymanimcTSQLSatement NVARCHAR(MAX)
,#DynamicColumns NVARCHAR(MAX);
SET #DynamicColumns = STUFF
(
(
SELECT ',' + QUOTENAME([Location])
FROM tLocation
GROUP BY [Location]
ORDER BY [Location]
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1
,1
,''
);
SET #DymanimcTSQLSatement = N'
SELECT *
FROM
(
SELECT L.Location
,C.City
,1
FROM tCityLocation CL
INNER JOIN tLocation L
ON CL.[LocationId] = L.[id]
INNER JOIN tCity C
ON CL.[CityId] = C.[id]
) DS (country, city, value)
PIVOT
(
MAX([value]) FOR [country] IN (' + #DynamicColumns +')
) PVT;';
EXECUTE sp_executesql #DymanimcTSQLSatement;
and here is the data I have used:
-- Creating Table tCity
CREATE TABLE tCity (
Id int,
City nvarchar(50)
);
-- Populating Table tCity with 10 records
INSERT INTO tCity (Id, City) VALUES (1, 'New York');
INSERT INTO tCity (Id, City) VALUES (2, 'Los Angeles');
INSERT INTO tCity (Id, City) VALUES (3, 'Paris');
INSERT INTO tCity (Id, City) VALUES (4, 'Tokyo');
INSERT INTO tCity (Id, City) VALUES (5, 'Sydney');
INSERT INTO tCity (Id, City) VALUES (6, 'Philadelphia');
INSERT INTO tCity (Id, City) VALUES (7, 'Rio de Janeiro');
INSERT INTO tCity (Id, City) VALUES (8, 'Cape Town');
INSERT INTO tCity (Id, City) VALUES (9, 'Beijing');
INSERT INTO tCity (Id, City) VALUES (10, 'Singapore');
-- Creating Table tLocation
CREATE TABLE tLocation (
Id int,
Location nvarchar(50)
);
-- Populating Table tLocation with 10 records
INSERT INTO tLocation (Id, Location) VALUES (1, 'United States');
INSERT INTO tLocation (Id, Location) VALUES (2, 'United States');
INSERT INTO tLocation (Id, Location) VALUES (3, 'France');
INSERT INTO tLocation (Id, Location) VALUES (4, 'Japan');
INSERT INTO tLocation (Id, Location) VALUES (5, 'Australia');
INSERT INTO tLocation (Id, Location) VALUES (6, 'United States');
INSERT INTO tLocation (Id, Location) VALUES (7, 'Brazil');
INSERT INTO tLocation (Id, Location) VALUES (8, 'South Africa');
INSERT INTO tLocation (Id, Location) VALUES (9, 'China');
INSERT INTO tLocation (Id, Location) VALUES (10, 'Singapore');
-- Creating Table tCityLocation
CREATE TABLE tCityLocation (
Id int,
CityId int,
LocationId int
);
INSERT INTO tCityLocation (Id, CityId, LocationId)
SELECT
ROW_NUMBER() OVER (ORDER BY tCity.Id),
tCity.Id, tLocation.Id
FROM tCity
JOIN tLocation
ON tCity.Id = tLocation.Id;
The idea is to built a dynamic PIVOT, where the PIVOT columns are the unique countries (in your case locations). If your SQL Server supports STRING_AGG, you can do this in different way:
SELECT #DynamicColumns = STRING_AGG(CAST(QUOTENAME([Location]) AS VARCHAR(MAX)), ',') WITHIN GROUP (ORDER BY [Location])
FROM
(
SELECT DISTINCT [Location]
FROM tLocation
) DS ([Location]);

Better way for answer to this question use pivot
First I get list Location of table Location
Second I get list Location of table tLocation For use in select
Because I need to use ISNULL for replace null with space
after use pivot for get result
result :Rows include List City and Column include Location
city
Asia
CRezah Rep.
Europe
France
GB
Germany
Japan
N.America
USA
NY
x
x
Prague
x
x
x
London
x
x
Tokio
x
x
--Get List Columns for Pivot
DECLARE #cols AS NVARCHAR(MAX),#scols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(Location) from tLocation
FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'' )
--can to use below Code for Replace null with space
select #scols = STUFF((SELECT distinct ',ISNULL(' + QUOTENAME(Location) +','' '') as '+ QUOTENAME(Location)
from tLocation FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'')
set #query = 'SELECT city ,'+#scols+' from
(
select cl.CityId,c.City,l.Location,''X'' as Value from tCityLocation cl
inner join tCity c on cl.CityId=c.Id
inner join tLocation l on cl.LocationId=l.Id
) x
pivot
(
max( value) for Location in (' + #cols + ')
) p
order by CityId
'
execute(#query)
You can to insert the basic data with the following codes
create table tCity(Id int, City nvarchar(50))
create table tLocation(Id int, Location nvarchar(50))
create table tCityLocation(Id int, CityId int, LocationId int)
insert into tCity
(id,City)
select 1 as id,'NY' union all select 2 as id,'Prague'
union all select 3 as id,'London' union all select 4 as id,'Tokio'
insert into tLocation (id,Location)
select 1,'USA' union all select 2,'CRezah Rep.' union all select 3,'France' union all select 4,'GB'
union all select 5,'Germany' union all select 6,'Europe' union all select 7,'N.America'
union all select 9,'Asia' union all select 10,'Japan'
insert into tCityLocation
(id,CityId,LocationId)
select 1,1,1 union all select 2,1,7 union all select 3,2,2 union all select 4,2,6 union all select 5,3,4 union all
select 6,3,6 union all select 7,4,9 union all select 8,4,10

Related

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/

concat a column fields of a table group by the fields of another table

I have two tables say t1 and t2 which join with testid.I need to concat val column of t2 if d1,d2 and id of table t1 is same.Please refer to the following tables.
CREATE TABLE #t1 (d1 varchar(100),d2 varchar(100),id int,testid int)
INSERT INTO #t1 (d1,d2,id,testid) VALUES ('p','q',1,101)
INSERT INTO #t1 (d1,d2,id,testid) VALUES ('r','s',2,102)
INSERT INTO #t1 (d1,d2,id,testid) VALUES ('p','q',1,103)
INSERT INTO #t1 (d1,d2,id,testid) VALUES ('r','s',1,104)
CREATE TABLE #t2 (testid int,val varchar(100))
INSERT INTO #t2 (testid,val) values (101,'x')
INSERT INTO #t2 (testid,val) values (102,'y')
INSERT INTO #t2 (testid,val) values (103,'z')
INSERT INTO #t2 (testid,val) values (104,'xx')
The result should be:
d1 d2 pid val
p q 1 x,z
r s 2 y
r s 1 xx
IF OBJECT_ID('tempdb.dbo.#t1') IS NOT NULL
DROP TABLE #t1
IF OBJECT_ID('tempdb.dbo.#t2') IS NOT NULL
DROP TABLE #t2
CREATE TABLE #t1 (d1 VARCHAR(100), d2 VARCHAR(100), id INT, testid INT)
INSERT INTO #t1 (d1, d2, id, testid)
VALUES ('p', 'q', 1, 101)
, ('r', 's', 2, 102)
, ('p', 'q', 1, 103)
, ('r', 's', 1, 104)
CREATE TABLE #t2 (testid INT, val VARCHAR(100))
INSERT INTO #t2 (testid, val)
VALUES (101, 'x')
, (102, 'y')
, (101, 'z')
, (104, 'xx')
SELECT *
FROM (
SELECT d1, d2, id, value = STUFF((
SELECT [text()] = ',' + val
FROM #t2
WHERE #t2.testid = #t1.testid
FOR XML PATH('')), 1, 1, '')
FROM #t1
) t
WHERE t.value IS NOT NULL
output -
d1 d2 id value
--- --- ---- ----------------
p q 1 x,z
r s 2 y
r s 1 xx

Multiple columns within the same SQL query

I have been working on this problem for a while now and I can't figure out what to do.
I have a huge SQL query with multiple joins and it gives me hundreds of thousands of records, which is perfect.
I then realized that I had 200 odd some records in another table that needs to be added to the first.
First table:
Field1 Field2 Field3
john smith 23 Boston
Mohammed Ali 45 New York
Stephanie Johnson 15 Los Angeles
New Table
Field1 OtherField1 OtherField2
Mark Khoury Null null
So I really only need to add the Field1 values from table two to the "bottom" of the first. All of the joins I made in the first query should also work for the values found in table two.
A union won't work because I only have on column to add. I would have to copy-paste the same query from the first table to get "Field2" and Field3" from the values of the second.
What I want it to look like is:
Field1 Field2 Field3
John Smith 23 Boston
Mohammed Ali 45 New York
Stephanie Johnson 15 Los Angeles
Mark Khoury 65 Houston
How can I go about doing this? I don't want to "JOIN" the tables, I want to unite them but only with one column.
Here is an example of what I mean:
Table one was created by doing something like the following:
SELECT table.value1 as Field1, table2.value2 as Field2, table3.value3 as Field3
FROM some_table as table
LEFT OUTER JOIN some_other_table as Table2 ON table.field = table2.field5
LEFT OUTER JOIN a_third_table as table3 ON table2.field2 = table3.field4
but now I have newTable with more Field1 values and I need to add those values to the first table.
I tried this:
SELECT COALESCE(table.value1, NewTable.value) as Field1, table2.value2 as Field2,
table3.value3 as Field3
FROM some_table as table
LEFT OUTER JOIN some_other_table as Table2 ON table.field = table2.field5
LEFT OUTER JOIN a_third_table as table3 ON table2.field2 = table3.field4, newTable
but this is giving me an exponential amount of results, where it should be giving me a few hundred more.
You could add a union with the first column and set the other columns as '' something like,
SELECT Field1, Field2
FROM table1
UNION
SELECT Field1, '' AS Field2
FROM table2
Would that get you what you needed?
Taking your example, would the below get you what you need?
SELECT table.value1 as Field1, table2.value2 as Field2, table3.value3 as Field3
FROM
(SELECT t.value1 as Field1 FROM some_table as t
UNION
SELECT t2.value1 as Field1 FROM some_table2 as t2) as table
LEFT OUTER JOIN some_other_table as Table2 ON table.field1 = table2.field5
LEFT OUTER JOIN a_third_table as table3 ON table2.field2 = table3.field4
Having the same idea as #rhollyer, here is a script that may produce what you're asking for.
DECLARE #Person TABLE
(
PersonID int,
DisplayName nvarchar(50)
)
DECLARE #PersonDetail TABLE
(
PersonID int,
Age int
)
DECLARE #PersonGeoInfo TABLE
(
PersonID int,
City nvarchar(200)
)
DECLARE #LostPersons TABLE
(
LostPersonID int,
DisplayName nvarchar(50),
Irrelevant1 decimal,
Irrelevant2 bit
)
INSERT INTO #Person (PersonID, DisplayName)
VALUES
(1, 'John Smith'),
(2, 'Mohammed Ali'),
(3, 'Stephanie Johnson')
INSERT INTO #PersonDetail(PersonID, Age)
VALUES
(1, 23),
(2, 45),
(3, 15),
(4, 65)
INSERT INTO #PersonGeoInfo(PersonID, City)
VALUES
(1, 'Boston'),
(2, 'New York'),
(3, 'Los Angeles'),
(4, 'Houston')
INSERT INTO #LostPersons(LostPersonID, DisplayName, Irrelevant1, Irrelevant2)
VALUES
(4, 'Mark Khoury', 9.5, 1)
DECLARE #Person TABLE
(
PersonID int,
DisplayName nvarchar(50)
)
DECLARE #PersonDetail TABLE
(
PersonID int,
Age int
)
DECLARE #PersonGeoInfo TABLE
(
PersonID int,
City nvarchar(200)
)
DECLARE #LostPersons TABLE
(
LostPersonID int,
DisplayName nvarchar(50),
Irrelevant1 decimal,
Irrelevant2 bit
)
INSERT INTO #Person (PersonID, DisplayName)
VALUES
(1, 'John Smith'),
(2, 'Mohammed Ali'),
(3, 'Stephanie Johnson')
INSERT INTO #PersonDetail(PersonID, Age)
VALUES
(1, 23),
(2, 45),
(3, 15),
(4, 65)
INSERT INTO #PersonGeoInfo(PersonID, City)
VALUES
(1, 'Boston'),
(2, 'New York'),
(3, 'Los Angeles'),
(4, 'Houston')
INSERT INTO #LostPersons(LostPersonID, DisplayName, Irrelevant1, Irrelevant2)
VALUES
(4, 'Mark Khoury', 9.5, 1)
SELECT P.DisplayName AS Field1, PD.Age AS Field2, PGI.City AS Field3
FROM (
SELECT P.PersonID AS PersonID, P.DisplayName AS DisplayName FROM #Person P
UNION
SELECT LP.LostPersonID AS PersonID, LP.DisplayName AS DisplayName FROM #LostPersons LP) AS P
LEFT OUTER JOIN #PersonDetail PD ON P.PersonID = PD.PersonID
LEFT OUTER JOIN #PersonGeoInfo PGI ON PD.PersonID = PGI.PersonID

How do I remove all but some records based on a threshold?

I have a table like this:
CREATE TABLE #TEMP(id int, name varchar(100))
INSERT INTO #TEMP VALUES(1, 'John')
INSERT INTO #TEMP VALUES(1, 'Adam')
INSERT INTO #TEMP VALUES(1, 'Robert')
INSERT INTO #TEMP VALUES(1, 'Copper')
INSERT INTO #TEMP VALUES(1, 'Jumbo')
INSERT INTO #TEMP VALUES(2, 'Jill')
INSERT INTO #TEMP VALUES(2, 'Rocky')
INSERT INTO #TEMP VALUES(2, 'Jack')
INSERT INTO #TEMP VALUES(2, 'Lisa')
INSERT INTO #TEMP VALUES(3, 'Amy')
SELECT *
FROM #TEMP
DROP TABLE #TEMP
I am trying to remove all but some records for those that have more than 3 names with the same id. Therefore, I am trying to get something like this:
id name
1 Adam
1 Copper
1 John
2 Jill
2 Jack
2 Lisa
3 Amy
I am not understanding how to write this query. I have gotten to the extent of preserving one record but not a threshold of records:
;WITH FILTER AS
(
SELECT id
FROM #TEMP
GROUP BY id
HAVING COUNT(id) >=3
)
SELECT id, MAX(name)
FROM #TEMP
WHERE id IN (SELECT * FROM FILTER)
GROUP BY id
UNION
SELECT id, name
FROM #TEMP
WHERE id NOT IN (SELECT * FROM FILTER)
Gives me:
1 Robert
2 Rocky
3 Amy
Any suggestions? Oh by the way, I don't care what records are preserved while merging.
You can do it using CTE
CREATE TABLE #TEMP(id int, name varchar(100))
INSERT INTO #TEMP VALUES(1, 'John')
INSERT INTO #TEMP VALUES(1, 'Adam')
INSERT INTO #TEMP VALUES(1, 'Robert')
INSERT INTO #TEMP VALUES(1, 'Copper')
INSERT INTO #TEMP VALUES(1, 'Jumbo')
INSERT INTO #TEMP VALUES(2, 'Jill')
INSERT INTO #TEMP VALUES(2, 'Rocky')
INSERT INTO #TEMP VALUES(2, 'Jack')
INSERT INTO #TEMP VALUES(2, 'Lisa')
INSERT INTO #TEMP VALUES(3, 'Amy')
SELECT *
FROM #TEMP;
WITH CTE(N) AS
(
SELECT ROW_NUMBER() OVER(PARTITION BY id ORDER BY id)
FROM #Temp
)
DELETE CTE WHERE N>3;
SELECT *
FROM #TEMP;
DROP TABLE #TEMP
I will change your select like this (not tested)
select name from #temp group by name having count(id) > 3
then you can implement your query in a delete statement using your select as a where clause
in inner query you can use row_number function over (partition by id)
and then in outer query you have to give condition like below
select id,name from (
SELECT id,name, row_number() over (partition by id order by 1) count_id FROM #test
group by id, name )
where count_id <=3
If i got your question right, you need to get rows when id occurrence 3 or more times
select t1.name,t1.id from tbl1 t1
inner join tbl1 t2 on t1.id = t2.id
group by t1.name, t1.id
having count(t1.id) > 2

how to get Related Records using LINQ

Hello I have this table structure:
**ProductsTable**
ProductID
ProductName
**CategoriesTable**
CategoryID
CategoryName
**ProductCategories**
ProductID
CategoryID
Each Product can belong to multiple categories. Now I need a way to find Related Products. But I want it in this way:
Let's say Product1 belong to Laptop, Accessories. So only those products who belong to both categories (not just one) can be retrieved.
SQL Query will work, however if you can give LINQ it will be best.
Thanks in Advance
Marc V.
Update
Here is my sql solution with setup:
declare #p table(id int, name varchar(10))
declare #c table(id int, name varchar(10))
declare #pc table(pid int, cid int)
insert into #p (id, name) values (1, 'laptop')
insert into #p (id, name) values (2, 'desktop')
insert into #p (id, name) values (3, 'milk')
insert into #c (id, name) values (1, 'computer')
insert into #c (id, name) values (2, 'device')
insert into #c (id, name) values (3, 'food')
insert into #pc (pid, cid) values (1, 1)
insert into #pc (pid, cid) values (1, 2)
--insert into #pc (pid, cid) values (1, 3)
insert into #pc (pid, cid) values (2, 1)
insert into #pc (pid, cid) values (2, 2)
insert into #pc (pid, cid) values (3, 3)
declare #productId int;
set #productId = 1;
select *
from #p p
where
--count of categories that current product shares with the source product
--should be equal to the number of categories the source product belongs to
(
select count(*)
from #pc pc
where pc.pid = p.id
and pc.cid in (
select cid from #pc pc
where pc.pid = #productId
)
) = (select count(*) from #pc pc where pc.pid = #productId)
and
p.id <> #productId