Trying to build an SQL Server query with a specific output - sql

I have two main tables with a joining table. One table has all of the main records, the second table has categories that the main records would be associated with. the link table. The joining table has entries with IDs from both the categories, and the main records, and it builds associations (main record id 2, to category id 245 as an example)
I am trying to build a query that outputs all of the main records, with all of the categories for each row of the main records, as some rows can have many categories.
What I would love it to do is output them in a delimited fashion so that I can keep it to one row per main record. Right now the best I seem to be able to do is a row for each category that main item has. example of what I want (highly simplified).
ID | Name | Category
-------------------------------------
2 | thing | shiny,special,explosive
What I get now is:
ID | Name | Category
-------------------------
2 | thing | shiny
2 | thing | special
2 | thing | explosive
etc.
Here is my current query in it's state - the reason there are so many columns being selected is there is many columns in the table, and I only need a few shown.
SELECT Attractions.ID
, Attractions.HotelName
, Attractions.Enabled
, Attractions.HotelAddress1
, Attractions.HotelAddress2
, Attractions.City
, Attractions.Prov
, Attractions.Country
, Attractions.PostalCode
, Attractions.Latitude
, Attractions.Longitude
, Attractions.Ratings
, Attractions.Phone
, Attractions.Fax
, Attractions.TollFree
, Attractions.Email
, Attractions.Website
, Attractions.ShowInSearch
, Attractions.MoreInfoCounter
, Attractions.ContactPerson
, Attractions.ContactPersonFirst
, Attractions.ContactPersonLast
, Attractions.Notes
, Attractions.SponsorID
, Attraction_Sub_Types.Name
FROM
dbo.Attractions_Attraction_Sub_Types_Link
INNER JOIN dbo.Attractions
ON Attractions_Attraction_Sub_Types_Link.AttractionID = Attractions.ID
INNER JOIN dbo.Attraction_Sub_Types
ON Attractions_Attraction_Sub_Types_Link.Sub_TypeID = Attraction_Sub_Types.ID
WHERE
Attractions.ShowInSearch = 1
ORDER BY
Attractions.ID
I had at first experimented with sub queries but I could never get one to validate or even where to start so I abandoned that.

THis is a sample of how to do this:
select 'test' as Test, 1 as Item
into #test
union select 'test2', 2
union select 'test', 3
union select NUll, 4
union select 'test', 5
select t2.test, STUFF((SELECT ', ' + cast(t1.Item as varchar (10) )
FROM #test t1 where t2.test = t1.test
FOR XML PATH('')), 1, 1, '')
from #test t2
group by t2.test

Use the COALESCE function. Try something like:
DECLARE #Category VARCHAR(8000)
SELECT #Category = COALESCE(#Category + ', ', '') + Category
FROM categories_table
WHERE Category IS NOT NULL

Related

SQL get top level object from joins

Working on a query right now where we want to understand which business is referring the most downstream orders for us. I've put together a very basic table for demonstration purposes here with 4 businesses listed. Bar and Donut were both ultimately referred by Foo and I want to be able to show Foo as a business has generated X number of orders. Obviously getting the the single referral for Foo (from Bar) and Bar (from Donut) are simple joins. But how do you go from Bar to get back to Foo?
I'll add that I've done some more googling this AM and found a few very similar questions about the top level parent and most of the responses suggest recursive CTE. It's been awhile since I've dug deep into SQL stuff, but 8 years ago I know these were not overly popular. Is there another way around this? Perhaps better to just store that parent ID on the order table at the time of order?
+----+--------+--------------------+
| Id | Name | ReferralBusinessId |
+----+--------+--------------------+
| 1 | Foo | |
| 2 | Bar | 1 |
| 3 | Donut | 2 |
| 4 | Coffee | |
+----+--------+--------------------+
WITH RECURSIVE entity_hierarchy AS (
SELECT id, name, parent FROM entities WHERE name = 'Donut'
UNION
SELECT e.id, e.name, e.parent FROM entities e INNER JOIN entity_hierarchy eh on e.id = eh.parent
)
SELECT id, name, parent FROM entity_hierarchy;
SQL Fiddle Example
Assuming you're using SQL Server, you could use a query like the one below to generate a hierarchical Id path for a particular business.
declare #tbl as table (Id int, Name varchar(30), ReferralBusinessId int)
insert into #tbl (id, Name, ReferralBusinessId) values
(1, 'Foo', null),
(2, 'Bar', 1),
(3, 'Donut', 2),
(4, 'Coffee', null);
;WITH business AS (
SELECT Id, Name, ReferralBusinessId
, 0 AS Level
, CAST(Id AS VARCHAR(255)) AS Path
FROM #tbl
UNION ALL
SELECT R.Id, R.Name, R.ReferralBusinessId
, Level + 1
, CAST(Path + '.' + CAST(R.Id AS VARCHAR(255)) AS VARCHAR(255))
FROM #tbl R
INNER JOIN business b ON b.Id = R.ReferralBusinessId
)
SELECT * FROM business ORDER BY Path

How to get data from mssql with similar description?

So I have table like:
id | description | code | unit_value | short
1 | awesome product DG | CODEB14 | null | BT
2 | awesome product | CODE14 | 5005 | NOBT
3 | product less awe BGO | CODEB15 | null | BT
4 | product less awe | CODE15 | 5006 | NOBT
And I need display 'unit_value ' for items with DG, BGO but need to base on items without DG, BGO. So item 'awesome product DG' have the same 'unit_value' as
'awesome product' item. But I can not assign value for items where 'short = BT'.
So what I have so far are two queries which some how I want to merge:
select value_i_need from my_table where short= 'BT'
select value_i_need from my_table where short!= 'BT' and description like '%awesome product%'
And I have no idea how to merge those two queries? Some suggestion would be very helpful.
You need to join two copies of the table together
CREATE TABLE #mytable
(
id INT,
description VARCHAR(50),
code VARCHAR(10),
unitvalue INT NULL,
short VARCHAR(10)
)
INSERT INTO #mytable
(
id,
description,
code,
unitvalue,
short
)
VALUES
(1, 'awesome product DG' , 'CODEB14' , null ,'BT'),
(2, 'awesome product' , 'CODE14' , 5005 ,'NOBT'),
(3, 'product less awe BGO' , 'CODEB15' , null ,'BT'),
(4, 'product less awe' , 'CODE15' , 5006 ,'NOBT');
SELECT a.description, a.code, b.description, b.code, b.short, b.unitvalue, a.description, a.short
FROM #myTable a
LEFT OUTER JOIN #myTable b ON a.description LIKE b.description + '%'
AND b.short != 'BT'
WHERE a.short = 'BT'
However, this is making a lot of assumptions i.e. that there is only one such item for each row, that you don't have products with similar names where the "like" would confuse the two. Also joining on a "like" is going to be slow if there is any kind of volume. So although this works on this trivial example data, I'm not sure I recommend you actually use it.
It feels to me like this data should not all be in the same table. You should have one table with the BT entries, and another with the NOBT entries and a foreign key to the BT table. Maybe? Its not totally clear what the data represents, but might point you in the right direction.
Do you just want or?
select value_i_need
from my_table
where short = 'BT' or
(short <> 'BT' and description like '%here is the name%')
You could use code like below. You need to use table aliases (T1 and T2 below) to help match the columns. This is a correlated sub-query assuming there is exactly one match. I'll point out that LIKE will cause problems with multiple rows returned if you have more than one product that matches.
select (
select unit_value
from my_table T2
WHERE T2.description like '%awesome product%'
AND T2.short = 'NOBT'
)
from my_table T1
where T1.short= 'BT' AND T1.description LIKE '%awesome product%'

Recursive view that sum value from double tree structure SQL Server

First sorry for numerous repost of my question, I'm new around and getting used to properly and clearly asking questions.
I'm working on a recursive view that sum up values from a double tree structure.
I have researched around and found many questions about recursive sums but none of their solutions seemed to work for my issue specifically.
As of now I have issues aggregating the values in the right cells, the logic being i need the sum of each element per year in it's parent and also the sum of all the years for a given element.
Here is a fiddle of my tables and actual script:
SQL Fiddle
And here is a screenshot of the output I'm looking for:
My question is:
How can I get my view to aggregate the value from child to parent in this double tree structure?
If I understand your question correctly, you are trying to get an aggregation at 2 different levels to show in a single result set.
Clarification Scenario:
Below is an over-simplified sample data set for what I believe you are trying to achieve.
create table #agg_table
(
group_one int
, group_two int
, group_val int
)
insert into #agg_table
values (1, 1, 6)
, (1, 1, 7)
, (1, 2, 8)
, (1, 2, 9)
, (2, 3, 10)
, (2, 3, 11)
, (2, 4, 12)
, (2, 4, 13)
Given the sample data above, you want want to see the following output:
+-----------+-----------+-----------+
| group_one | group_two | group_val |
+-----------+-----------+-----------+
| 1 | NULL | 30 |
| 1 | 1 | 13 |
| 1 | 2 | 17 |
| 2 | NULL | 46 |
| 2 | 3 | 21 |
| 2 | 4 | 25 |
+-----------+-----------+-----------+
This output can be achieved by making use of the group by grouping sets
(example G. in the link) syntax in SQL Server as shown in the query below:
select a.group_one
, a.group_two
, sum(a.group_val) as group_val
from #agg_table as a
group by grouping sets
(
(
a.group_one
, a.group_two
)
,
(
a.group_one
)
)
order by a.group_one
, a.group_two
What that means for your scenario, is that I believe your Recursive-CTE is not the issue. The only thing that needs to change is in the final select query from the entire CTE.
Answer:
with Temp (EntityOneId, EntityOneParentId, EntityTwoId, EntityTwoParentId, Year, Value)
as
(
SELECT E1.Id, E1.ParentId, E2.Id, E2.ParentId, VY.Year, VY.Value
FROM ValueYear AS VY
FULL OUTER JOIN EntityOne AS E1
ON VY.EntityOneId = E1.Id
FULL OUTER JOIN EntityTwo AS E2
ON VY.EntityTwoId = E2.Id
),
T (EntityOneId, EntityOneParentId, EntityTwoId, EntityTwoParentId, Year, Value, Levels)
as
(
Select
T1.EntityOneId,
T1.EntityOneParentId,
T1.EntityTwoId,
T1.EntityTwoParentId,
T1.Year,
T1.Value,
0 as Levels
From
Temp
As T1
Where
T1.EntityOneParentId is null
union all
Select
T1.EntityOneId,
T1.EntityOneParentId,
T1.EntityTwoId,
T1.EntityTwoParentId,
T1.Year,
T1.Value,
T.Levels +1
From
Temp
AS T1
join
T
On T.EntityOneId = T1.EntityOneParentId
)
Select
T.EntityOneId,
T.EntityOneParentId,
T.EntityTwoId,
T.EntityTwoParentId,
T.Year,
sum(T.Value) as Value
from T
group by grouping sets
(
(
T.EntityOneId,
T.EntityOneParentId,
T.EntityTwoId,
T.EntityTwoParentId,
T.Year
)
,
(
T.EntityOneId,
T.EntityOneParentId,
T.EntityTwoId,
T.EntityTwoParentId
)
)
order by T.EntityOneID
, T.EntityOneParentID
, T.EntityTwoID
, T.EntityTwoParentID
, T.Year
FYI - I believe the sample data did not have the records necessary to match the expected output completely, but the last 20 records in the SQL Fiddle match the expected output perfectly.

SQL SELECT with JOINS and Multiple Rows for one Column

The issue at hand is that I have a basic query (from a document software database), taking from multiple tables with some LEFT JOINS, but I have one column in question that needs to take from a table where there are multiple results per unique document id (DocGUID).
CURRENT QUERY
SELECT doc.[Doc #]
, '' AS 'Authors'
, ud.[Lead Author]
, doc.[Title]
, ud.[Publication]
, ud.[Citation]
, ud.[Year]
, ud.[Month]
, ud.[Comments]
, notes.[Note]
FROM [tblDocuments] doc
LEFT JOIN [tblNotes] notes ON notes.[DocGUID] = doc.[DocGUID]
LEFT JOIN [tblUserData] ud ON ud.[MasterGUID] = doc.[DocGUID]
WHERE doc.[DocGUID] = '12345678'
As you can see, I have simply queried '' for "Authors". Here's where my issue comes in. I have a table named tblMultiValues where there are two or more authors listed per DocGUID.
Table Example: (for tblMultiValues)
|------|-------------|-------------|-------------------|
| Id | DocGUID | FieldName | Value |
|------|-------------|-------------|-------------------|
| 123 | 12345678 | Authors | Collins, Nick |
| 456 | 12345678 | Authors | Williams, Robert |
| 321 | 87654321 | Authors | Smith, Kate |
| 654 | 87654321 | Authors | Hanks, Tom |
|------|-------------|-------------|-------------------|
So, what I want to show for the 2nd column of 'Authors', is the result of:
Collins, Nick; Williams, Robert
Specifically for DocGUID of '12345678'
How might one go about doing this, mixed in with the query that is already built?
(I hope this was enough info... if more is needed, please advise).
-Nick
:::EDIT:::
I was able to get things running with the following code... (very well guided from the answer given by #mohan111
SELECT DISTINCT
STUFF((
SELECT '; ' + mv2.Value
FROM [dbo].[tblMultiValues] mv2
WHERE mv1.DocGUID = mv2.DocGUID
FOR XML PATH ('')),1,2,'') AS 'Authors', mv1.FieldName, mv1.DocGUID
INTO #TempMultival
FROM [dbo].[tblMultiValues] mv1
SELECT doc.[Doc #]
, tmv.[Authors]
, ud.[Lead Author]
, doc.[Title]
, ud.[Publication]
, ud.[Citation]
, ud.[Year]
, ud.[Month]
, ud.[Comments]
, notes.[Note]
FROM [tblDocuments] doc
LEFT JOIN [tblNotes] notes ON notes.[DocGUID] = doc.[DocGUID]
LEFT JOIN [tblUserData] ud ON ud.[MasterGUID] = doc.[DocGUID]
LEFT JOIN #TempMultiVal tmv ON tmv.DoCGUID = doc.[DocGUID]
DROP TABLE #TempMultiVal
Declare #table TABLE
(
Id INT,
DocGUID int,
FieldName VARCHAR(25),
Value VARCHAR(200)
);
INSERT INTO #table
( Id,
DocGUID,
FieldName,
Value
)
VALUES
(123,12345678,'Authors','Collins, Nick'),
(456,12345678,'Authors','Williams, Robert'),
(321,87654321,'Authors','Smith, Kate'),
(654,87654321,'Authors','Hanks, Tom');
Select distinct DocGUID,
(SELECT
Substring((SELECT ', ' + CAST(i.id AS VARCHAR(1024))
FROM
#table i
WHERE i.DocGUID = tt.DocGUID
ORDER BY i.id
FOR XML PATH('')), 3, 10000000) AS list) AS ID,
FieldName,
STUFF((Select distinct t.Value + ','
from #table t
where t.DocGUID = tt.DocGUID
FOR XML PATH(''),TYPE).value('.', 'NVARCHAR(MAX)')
, 1, 0, ' ') from #table tt

Select query to get all data from junction table to one field

I have 2 tables and 1 junction table:
table 1 (Log): | Id | Title | Date | ...
table 2 (Category): | Id | Title | ...
junction table between table 1 and 2:
LogCategory: | Id | LogId | CategoryId
now, I want a sql query to get all logs with all categories title in one field,
something like this:
LogId, LogTitle, ..., Categories(that contains all category title assigned to this log id)
can any one help me solve this? thanks
Try this code:
DECLARE #results TABLE
(
idLog int,
LogTitle varchar(20),
idCategory int,
CategoryTitle varchar(20)
)
INSERT INTO #results
SELECT l.idLog, l.LogTitle, c.idCategory, c.CategoryTitle
FROM
LogCategory lc
INNER JOIN Log l
ON lc.IdLog = l.IdLog
INNER JOIN Category c
ON lc.IdCategory = c.IdCategory
SELECT DISTINCT
idLog,
LogTitle,
STUFF (
(SELECT ', ' + r1.CategoryTitle
FROM #results r1
WHERE r1.idLog = r2.idLog
ORDER BY r1.idLog
FOR XML PATH ('')
), 1, 2, '')
FROM
#results r2
Here you have a simple SQL Fiddle example
I'm sure this query can be written using only one select, but this way it is readable and I can explain what the code does.
The first select takes all Log - Category matches into a table variable.
The second part uses FOR XML to select the category names and return the result in an XML instead of in a table. by using FOR XML PATH ('') and placing a ', ' in the select, all the XML tags are removed from the result.
And finally, the STUFF instruction replaces the initial ', ' characters of every row and writes an empty string instead, this way the string formatting is correct.