How can I join these two tables into the same Sql result - sql

I'm trying to generate a SQL query that can join two tables together and return the result .. but the second table is 'flattened'. I'm not sure if that's the correct technical term. Is it denormalized?
Anyways, can someone suggest how I could do this?
Table: Users
UserId Name
1 Pure.Krome
2 John
3 Jill
4 Jane
Table: UserAliases
UserAliasId UserId Alias
1 1 Idiot
2 1 PewPew
3 3 BlahBlahBlah
Desired results
UserId Name Aliases
1 Pure.Krome Idiot PewPew
2 John
3 Jill BlahBlahBlah
4 Jane
Please note:
A user does NOT need to have an alias. So that's a zero->many relationship (outer join)
The delimiter for the flattening of the 2nd table is a SPACE. If an alias has a space, bad luck for me. (Consider it, bad data).
Another example of my problem is to think of a StackOverflow question + tags.

http://groupconcat.codeplex.com/ has a clone of MySQL's GROUP_CONCAT() implemented as a CLR aggregation function. I guess the SQL is not the problem, but I might as well:
SELECT
[Users].[UserId] AS UserId,
[Users].[Name] AS Name,
GROUP_CONCAT_D([UserAliases].[Alias]," ") AS Aliases
FROM [Users]
OUTER JOIN [UserAliases] ON [Users].[UserId]=[UserAliases].[UserId]
or similar.

This is not tested but give it a try. I have no server here.
SELECT a.UserID,
a.[Name],
coalesce(NewTable.NameValues, '') Aliases
FROM Users a LEFT JOIN
(
SELECT UserID,
STUFF((
SELECT ' ' + [Name]
FROM UserAliases
WHERE ( UserID = Results.UserID )
FOR XML PATH('')), 1, 2, '') AS NameValues
FROM UserAliases Results
GROUP BY UserID
) NewTable
on a.UserID = NewTable.UserID
Here's SQL Fiddle Output

FOR XML PATH is handy in this situation:
SELECT UserID, Name
, LTRIM(RTRIM((SELECT ' ' + Alias
FROM UserAliases WHERE UserID = u.UserID
FOR XML PATH('')))) AS Aliases
FROM Users u

Related

Create view with JSON array based on many to many table

I have a typical table with users. I have also a many to many table where first column is UserId and second BusinessId. I want to create a view with users where their businessId will be as json.
I tried something like this:
SELECT
ISNULL(CAST(u.[Id] AS INT), 0) AS [Id]
,(SELECT BusinessId FROM [TableA].[dbo].[user_business_entities] WHERE UserId = u.Id FOR JSON AUTO) AS BusinessEntityIds
FROM
[TableA].[dbo].[core_users] u
But in view I get this:
Id
BusinessEntityIds
1
[{"BusinessId":1925},{"BusinessId":1926}]
2
[{"BusinessId":15}]
It's pretty good, but it would be best if json had only values, no key name i.e only ids without "BusinessId":
Id
BusinessEntityIds
1
[1925, 1926]
2
[15]
How can I do this?
Two quick options: First is for <=2016 and the 2nd is 2017+
Never understood why MS never provided this functionality of a simple ARRAY.
Option 1 <=2016
Select ID
,BusinessEntityIds = '['+stuff((Select concat(',',BusinessEntityIds)
From YourTable
Where ID=A.ID
For XML Path ('')),1,1,'')+']'
From YourTable A
Group By ID
Option 2 2017+
select ID,
BusinessEntityIds = '['+string_agg(BusinessEntityIds, ',') +']'
from YourTable
group by ID
Both Results Are
ID BusinessEntityIds
1 [1925,1926]
2 [15]

SQL Server [PATSTAT] query | Multiple charindex values &

Hello Stack Overflow Community.
I am retrieving data with SQL from PATSTAT (patent data base from the European Patent Office). I have two issues (see below). For your info the PATSAT sql commands are quite limited.
I. Charindex with multiple values
I am looking for specific two specific patent groups ["Y02E" and "Y02C"] and want to retrieve data on these. I have found that using the charindex function works if I insert one group;
and charindex ('Y02E', cpc_class_symbol) > 0
But if I want to use another charindex function the query just times out;
and charindex ('Y02E', cpc_class_symbol) > 0 or charindex ('Y02C', cpc_class_symbol) >0
I am an absolute SQL rookie but would really appreciate your help!
II. List values from column in one cell with comma separation
Essentially I want to apply what I found as the "string_agg"-command, however, it does not work for this database. I have entries with a unique ID, which have multiple patent categories. For example:
appln_nr_epodoc | cpc_class_symbol
EP20110185794 | Y02E 10/125
EP20110185794 | Y02E 10/127
I would like to have it like this, however:
appln_nr_epodoc | cpc_class_symbol
EP20110185794 | Y02E 10/125, Y02E 10/127
Again, I am very new to sql, so any help is appreciated! Thank you!
I will also attach the full code here for transparency
SELECT a.appln_nr_epodoc, a.appln_nr_original, psn_name, person_ctry_code, person_name, person_address, appln_auth+appln_nr,
appln_filing_date, cpc_class_symbol
FROM
tls201_appln a
join tls207_pers_appln b on a.appln_id = b.appln_id
join tls206_person c on b.person_id = c.person_id
join tls801_country on c.person_ctry_code= tls801_country.ctry_code
join tls224_appln_cpc on a.appln_id = tls224_appln_cpc.appln_id
WHERE appln_auth = 'EP'
and appln_filing_year between 2005 and 2012
and eu_member = 'Y'
and granted = 'Y'
and psn_sector = 'company'
and charindex ('Y02E', cpc_class_symbol) > 0
For your part 2 here is a sample data i created
And here is the code. It gives me YOUR requested output.
create table #test_1 (
appln_nr_epodoc varchar(20) null
,cpc_class_symbol varchar(20) null
)
insert into #test_1 values
('EP20110185794','Y02E 10/125')
,('EP20110185794','Y02E 10/127')
,('EP20110185795','Y02E 10/130')
,('EP20110185796','Y02E 20/140')
,('EP20110185796','Y02E 21/142')
with CTE_1 as (select *
from (
select *
,R1_1 = Rank() over(partition by appln_nr_epodoc order by cpc_class_symbol )
from #test_1
) as a
where R1_1 = 1
)
,CTE_2 as (select *
from (
select *
,R1_1 = Rank() over(partition by appln_nr_epodoc order by cpc_class_symbol )
from #test_1
) as a
where R1_1 = 2 )
select a.appln_nr_epodoc
,a.cpc_class_symbol+','+c.cpc_class_symbol
from CTE_1 a
join CTE_2 c on c.appln_nr_epodoc = a.appln_nr_epodoc
Out put

How Make a Hierarchical Selection with SQL Query

I have a problem in creating a SQL Query as follows :
I Have 2 Tables with following Specification and data:
http://dc699.4shared.com/img/lgtP3N_4ce/s3/144c7252ff8/SQL1.jpg
I want to create a SQL Select Query to return for me a Hierarchical Model Like this :
For example if the SID is 3 it should return for me this :
http://dc699.4shared.com/img/8UufpK2-ce/s3/144c7255af0/SQL2.jpg
Because the Num 3 in structure table related to data 7,8,9 and 9 is related to 10,11(Note that No 9 is related to 3 or in other words 9 is subset of 3)
Can anyone help me to create this Query? I have try for 2 weeks but I failed :(
Thanks so much
You can also try an Rank solution like this one
WITH Personel_Structure AS
(
SELECT [SID],MID, RANK() OVER(PARTITION BY [SID] ORDER BY MID ASC) AS POS
FROM Structure
WHERE [SID] = 3
)
SELECT [SID],MID
FROM Personel_Structure
ORDER BY POS ASC
I have script this against the structure table if you need to do a join to the personel table that should be easy from here. Just join the the tables in the CTE.
Untested answer, and it does not include the root member for readability and because your examples in the question and comments are inconsistent. This should get you going.
I made the query starting with root = 1
WITH members (id)
AS
(SELECT MID as id FROM structure WHERE SID = 1
UNION ALL
SELECT MID as id
FROM members
INNER JOIN structure ON (members.id = structure.SID)
)
SELECT members.ID FROM members;
members is the intermediary table created by the CTE (WITH...)
sqlfiddle

SQL Join / Pivot / Unpivot = Madness

So, I've done quite a bit of searching and fiddling and can't quite find a solution. Maybe my situation is unique - or more likely I just don't know what the heck I'm doing. I'm much closer than when I started, so that's uplifting. Anyway - here we go braintrust- any assistance is much appreciated.
I need to join 2 lookup tables that look like this (not enough rep points yet to post images so here's my pretend tables):
Social Network Member [table]
member_id social_network_id connection_id_string
16972 1 www.linkedin.com/somename
16972 2 www.twitter.com/somename
16972 3 www.facebook.com/somename
180301 1 www.linkedin.com/anothername
Social Network [table]
social_network_id name calling_string
1 Linkedin www.linkedin.com
2 Twitter www.twitter.com
3 Facebook www.facebook.com
This is what I want. I've tried a number of things including pivots and unpivots, cross apply - but I cant seem to get this result:
member_id linkedin facebook twitter
16972 www.linkedin.com/somename www.facebook.com/somename www.twitter.com/somename
I'll be able to work with that, I have no use for the social_network_id or calling_string after the join. Here's my query that's not quite doing the job.
SELECT member_id, [facebook],[linkedin],[myspace],[twitter]
FROM (
SELECT member_id,name,social_network_id,calling_string,connection_id_string
FROM social_network_member INNER JOIN
social_network ON social_network_member.social_network_id = social_network.social_network_id
CROSS APPLY (VALUES ('NAME',name),
('CONNECTION STRING', connection_id_string),
('CALLING STRING',calling_string))
Unpivoted(club_id,member_id)) as Sourcetable
Pivot (MAX(connection_id_string) For name in([facebook],[linkedin],[myspace],[twitter])) AS PVT
The best I can tell is the cross apply really isn't doing anything. I kind of guessed on the syntax there..can you tell?
This is what I'm getting (somewhat typical from what I've been seeing in searches):
member_id facebook linkedin myspace twitter
16972 NULL www.linkedin.com/somename NULL NULL
16972 www.facebook.com/somename NULL NULL NULL
...
...
Is what I want even possible? Any pointers on how to get there? Is my query all jacked up?
Thanks in advance Ladies and Gents.
I forgot to mention this earlier, but I'm using SQL server 2012 - SSMS.
RESOLVED I used the answer provided by Bluefeet below and it worked like a charm. Also thanks to Cha for taking the time to help.
Your current query is really close. If your tables above are the correct structure, then it doesn't seem that you need to use CROSS APPLY because you don't have anything that needs to be unpivoted.
If you remove the CROSS APPLY, then you can easily get the result using PIVOT:
SELECT member_id, [facebook],[linkedin],[myspace],[twitter]
FROM
(
SELECT m.member_id,
n.name,
m.connection_id_string
FROM social_network_member m
INNER JOIN social_network n
ON m.social_network_id = n.social_network_id
) d
pivot
(
max(connection_id_string)
for name in ([facebook],[linkedin],[myspace],[twitter])
) piv;
See SQL Fiddle with Demo.
If you have an unknown number of values, then you can use dynamic SQL:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(name)
from social_network
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT member_id, ' + #cols + '
from
(
SELECT m.member_id,
n.name,
m.connection_id_string
FROM social_network_member m
INNER JOIN social_network n
ON m.social_network_id = n.social_network_id
) x
pivot
(
max(connection_id_string)
for name in (' + #cols + ')
) p '
execute sp_executesql #query;
See SQL Fiddle with Demo
I think it is a very simple PIVOT case. You do not need to complicate it with CROSS APPLY/JOIN stuff at all. The query as simple as this will do:
SELECT member_id, [facebook],[linkedin],[myspace],[twitter]
FROM (
SELECT member_id,name,connection_id_string
FROM social_network_member snm INNER JOIN
social_network sn ON snm.social_network_id = sn.social_network_id
) as Sourcetable
Pivot (MAX(connection_id_string) For [name] in([facebook],[linkedin],[myspace],[twitter])) AS PVT
A hint: do not include unnecessary columns in your SourceTable for PIVOT
SQL Fiddle

Find incorrect records by Id

I am trying to find records where the personID is associated to the incorrect SoundFile(String). I am trying to search for incorrect records among all personID's, not just one specific one. Here are my example tables:
TASKS-
PersonID SoundFile(String)
123 D10285.18001231234.mp3
123 D10236.18001231234.mp3
123 D10237.18001231234.mp3
123 D10212.18001231234.mp3
123 D12415.18001231234.mp3
**126 D19542.18001231234.mp3
126 D10235.18001234567.mp3
126 D19955.18001234567.mp3
RECORDINGS-
PhoneNumber(Distinct Records)
18001231234
18001234567
So in this example, I am trying to find all records like the one that I indented. The majority of the soundfiles like '%18001231234%' are associated to PersonID 123, but this one record is PersonID 126. I need to find all records where for all distinct numbers from the Recordings table, the PersonID(s) is not the majority.
Let me know if you need more information!
Thanks in advance!!
; WITH distinctRecordings AS (
SELECT DISTINCT PhoneNumber
FROM Recordings
),
PersonCounts as (
SELECT t.PersonID, dr.PhoneNumber, COUNT(*) AS num
FROM
Tasks t
JOIN distinctRecordings dr
ON t.SoundFile LIKE '%' + dr.PhoneNumber + '%'
GROUP BY t.PersonID, dr.PhoneNumber
)
SELECT t.PersonID, t.SoundFile
FROM PersonCounts pc1
JOIN PersonCounts pc2
ON pc2.PhoneNumber = pc1.PhoneNumber
AND pc2.PersonID <> pc1.PersonID
AND pc2.Num < pc1.Num
JOIN Tasks t
ON t.PersonID = pc2.PersonID
AND t.SoundFile LIKE '%' + pc2.PhoneNumber + '%'
SQL Fiddle Here
To summarize what this does... the first CTE, distinctRecordings, is just a distinct list of the Phone Numbers in Recordings.
Next, PersonCounts is a count of phone numbers associated with the records in Tasks for each PersonID.
This is then joined to itself to find any duplicates, and selects whichever duplicate has the smaller count... this is then joined back to Tasks to get the offending soundFile for that person / phone number.
(If your schema had some minor improvements made to it, this query would have been much simpler...)
here you go, receiving all pairs (PersonID, PhoneNumber) where the person has less entries with the given phone number than the person with the maximum entries. note that the query doesn't cater for multiple persons on par within a group.
select agg.pid
, agg.PhoneNumber
from (
select MAX(c) KEEP ( DENSE_RANK FIRST ORDER BY c DESC ) OVER ( PARTITION BY rt.PhoneNumber ) cmax
, rt.PhoneNumber
, rt.PersonID pid
, rt.c
from (
select r.PhoneNumber
, t.PersonID
, count(*) c
from recordings r
inner join tasks t on ( r.PhoneNumber = regexp_replace(t.SoundFile, '^[^.]+\.([^.]+)\.[^.]+$', '\1' ) )
group by r.PhoneNumber
, t.PersonID
) rt
) agg
where agg.c < agg.cmax
;
caveat: the solution is in oracle syntax though the operations should be in the current sql standard (possibly apart from regexp_replace, which might not matter too much since your sound file data seems to follow a fixed-position structure ).