emulate group_concat in MSSQL, ambiguous column name? - sql

I am currently trying to simulate the group_concat function in MySQL to MSSQL. I have followed code formats found in here and here. The problem is, when I try to execute the query, I get the message Ambiguous column name for my column RoleID. Here is my query:
select UserName, RoleID from tb_UserInRoles
cross apply(
select RoleName from tb_Roles
where tb_UserInRoles.RoleID = tb_Roles.RoleID
for XML Path('')
) fxMerge (RoleID) group by UserName, RoleID
I'd like to know why this particular code format present the Ambiguous column name error message. I need to make this query work and understand it. Thanks in advance for the help.
I plan on using this in a many-to-many relationship table, wherein users of a system can have multiple roles, like this:
| User | Role |
|--------|---------|
| JamesP | Maker |
| JamesP | Approver|
| JamesP | Admin |
I want the result query to be like this:
| User | Role |
|--------|--------------------------|
| JamesP | Maker, Approver, Admin |

Try this:
SELECT UIR.UserName, MAX(STUFF(fxMerge.RoleID, 1, 1, ''))
FROM tb_UserInRoles UIR
CROSS APPLY(
SELECT ',' + RoleName
FROM tb_UserInRoles UIR1
INNER JOIN tb_Roles RM ON UIR1.RoleID = RM.RoleID
WHERE UIR.UserName = UIR1.UserName
FOR XML PATH('')
) fxMerge (RoleID)
GROUP BY UIR.UserName

Related

SQL Group Multiple Results from Single Table

I have a table that contains a line entry for each item that I need to group into an output with all the values of multiple rows that have the same uniqueID into one column result. The ItemType will be different but the UniqueID and OtherData shouldn't change as it's tied directly to the UniqueID, but I'm not 100% sure as there are well over 2M lines in this DB. I have seen similar questions and they would appear to do what I would like them to do, but the answers are over simplified and usually only include the unique id and the field they want on one line. I need to include about 5 other columns but I don't need to any anything fancy to them. Just trying to group results from the one column as well as return the other columns (that are likely not never be different).
To over simplify the data set this is what it looks like followed by what I'd like to do.
Example Table:
UniqueID | ItemType | OtherData
----------------------------------
1234 | apples | 123.1.123.1
1234 | oranges | 123.1.123.1
2233 | red fish | 123.5.67.2
1234 | grapes | 123.1.123.1
2233 | blue fish | 123.5.67.2
Desired Result:
UniqueID | ItemType | OtherData
----------------------------------
1234 | apples, oranges, grapes | 123.1.123.1
2233 | red fish, blue fish | 123.5.67.2
I've tried a couple versions of SELECT DISTINCT and GROUP BY but that either returns the same as if I didn't or some other undesirable result. Also tried STRING_AGG but that only works on MSSQL2017.
Any help you can provide would be much appreciated, thank you!
Building on the answer from the previous link you can create a cte then execute the query
This will given you the
SELECT Main.UniqueID,
LEFT(Main.ItemTypes,Len(Main.ItemTypes)-1) As "ItemTypes"
FROM
(
SELECT DISTINCT ST2.UniqueID,
(
SELECT ST1.ItemType + ',' AS [text()]
FROM dbo.TheTable ST1
WHERE ST1.UniqueID = ST2.UniqueID
ORDER BY ST1.UniqueID
FOR XML PATH (''), TYPE
).value('text()[1]','nvarchar(max)') ItemTypes
FROM dbo.TheTable ST2
) [Main]
Once you have that you can build this into a cte with the with statement then join back on the table to get the rest of the data.
with ItemTypes as
(
SELECT Main.UniqueID,
LEFT(Main.ItemTypes,Len(Main.ItemTypes)-1) As "ItemTypes"
FROM
(
SELECT DISTINCT ST2.UniqueID,
(
SELECT ST1.ItemType + ',' AS [text()]
FROM dbo.TheTable ST1
WHERE ST1.UniqueID = ST2.UniqueID
ORDER BY ST1.UniqueID
FOR XML PATH (''), TYPE
).value('text()[1]','nvarchar(max)') ItemTypes
FROM dbo.TheTable ST2
) [Main]
)
Select Distinct TheTable.UniqueID, ItemTypes.ItemTypes, TheTable.OtherData
from TheTable join ItemTypes
on (TheTable.UniqueID = ItemTypes.UniqueID)
Results
UniqueID ItemTypes OtherData
--------- -------------------------- --------------------------------
1234 apples,oranges,grapes OtherData
2233 red fish,blue fish OtherData
There are a few expensive operations this will be an expensive query to run. but with 2million rows should be ok with a good server.
What you need is a group concat query in MySQL.
Your query will be
select UniqueID, GROUP_CONCAT(ItemType) ItemTypes, GROUP_CONCAT( DISTINCT OtherData) Otherdata from ExampleTable GROUP BY UniqueID;
A sample reference you can check here:
What group concat does is that it will group all column values against that UniqID col and mark them in a comma separated format. Link to read more in depth about group concat can be found here: Link
Group by all columns except for the item type. Then use the string aggregation function on the item type. In SQL Server this is STRING_AGG, but as you are using an antique version of the DBMS, you will have to emulate it. I am showing the proper query with STRING_AGGhere. Use Google or stackoverflow to see how it is emulated in your old SQL Server version.
select
uniqueid,
string_agg(itemtype, ', ') as itemtypes
otherdata
from mytable
group by uniqueid, otherdata
order by uniqueid, otherdata;
Two remarks:
UniqueID is a funny name for an ID that is not unique but occurs multiple times in the table. Misnomers like this can lead to errors and bad maintainability.
As to "OtherData shouldn't change as it's tied directly to the UniqueID": This indicates that your data model is flawed and your database table is not normalized. You should have two tables instead, one for the unique data, one for the details.

SQL field data addition

I am just wondering if it is possible to do something and as I cannot find any information about it:
let's say I have a field that I want to concatenate values to it:
For example
table 'test'
id | name |  surname
01 |  georges |  Michael
and I am trying to add information about this field like :
table 'test'
id | name | surname
01 | georges, rick | Michael
Do I need to update, insert or alter this 'test'.'name' with a second value(in this case 'rick')? Is it even possible to do that or will I need to create another related table in order to link 'rick' with 'georges'?
I know that if it is possible I will have to "insert" the comma as well but I do not know how.
SQL Server:
UPDATE test SET name = name + ', Rick' WHERE id = '01'
If you need to pull Rick from another table, you could do something like this:
UPDATE t
SET t.name = t.name + ', ' + o.othername
FROM test t
JOIN othername o ON t.id = o.id
WHERE t.id = '01'
And if you were looking for further posts/info on the topic, I'd suggest googling sql server string concatenation

How to select all the offers a user earned?

I am trying to do a SELECT to get the offers a certain user have earned. However, I cannot figure how to do it.
I have three tables
user: id | name
offer: id | name
user_offer: id | user_id | offer_id
How do I select all offer the user 1 has?
This should work:
SELECT offer.name
FROM offer INNER JOIN user_offer
ON user_offer.offer_id=offer.id
WHERE user_offer.user_id='1'

How to select distinct email engine provider from database (SQL server 2008)

Suppose a table is having lots of email Ids. We need the distinct email engine service providers. Like for an example..
id | EmailID
-------------
1 | aa#gmail.com
2 | bb#yahoo.com
3 | cc#outlook.com
4 | dd#aol.com
5 | ee#gmail.com
So we saw, four(4) distinct email ID providers are there Gmail,Yahoo,Outlook,AOL.
What SQL query should we use to find out the distinct email engine provider (i.e. where this EmailID after '#' are different and could be same after .com)
Kindly help me.
select Distinct substring(EmailID,charindex('#',EmailID,1)+1,len(EmailId))
from Table1
If you want extract only words like gmail,yahoo,outlook,outlook
Then try the below Query.
select
Distinct
substring(EmailID,
charindex('#',EmailID,1)+1,
charindex('.',EmailID,charindex('#',EmailID,1)+1)-charindex('#',EmailID,1)-1)
from Table1

SQL Select based on Link Field

I feel like an idiot asking this...
Table 1: users
id serial
person integer
username char(32)
Table 2:persons
id serial
name char(16)
Can I run a query that returns the name field in persons by providing the username in users?
users
1 | 1 | larry123
persons
1 | larry
2 | curly
SQL?
select name from persons where users.person=persons.id and users.username='larry123';
with the desired return of
larry
I have been doing it with two passes until now and think maybe a nested select using a join is what I need
1 | larry
It sounds like you're asking how to do a join in SQL:
SELECT
name
FROM
users JOIN persons ON (users.person = persons.id)
WHERE
users.username = 'larry123';
that is almost the query you wrote. All you were missing was the join clause. You could also do that join like this:
SELECT name
FROM users, persons
WHERE
users.person = persons.id
AND users.username = 'larry123';
I suggest finding a well-written introduction to SQL.