How to generate a hyperlink tag to each string in column, to create a tag cloud - sql

I have a table in SQL Server that stores info from a blog, so each record is a post. One of the columns stores the tags related to each post.
I need to create a tag for each tag stored in that column, they are separated with a comma ','.
For example: For the record 1, the column "tags" stores "cars,planes,boats".
I need to generate a column upon SELECT command that will write this:
cars<a><a href="blog-tags.aspx?tag=planes">planesboats
Any help would be highly appreciated! Thanks

If there's some kind of coding layer between the data and the user, then it's probably best to do this in the coding layer.
If you really must do it in sql, you could first convert the column into a separate temporary table, then join with the temporary table (and select accordingly)
INSERT INTO #tempTable(primaryKey, data)
SELECT yt.primaryKey, s.data
FROM
YourTable yt
inner join dbo.Split(yt.tags, ',') s
Relies on a split function such as found here: split function (which isn't a very fast one... but will suffice)
Then....
Select yt.*,
'<a href="blog-tags.aspx?tag=' + t.data + '">' + t.data + '<a>' as Link
from
YourTable yt
inner join #tempTable t on yt.PrimaryKey = t.PrimaryKey

Related

SQL to update rows to remove words with less than N characters

I have a TAGS column in my Products table in SQL Server. In my web project I split them with space, for example:
"web web_design website website_design"
=> 1.web 2. web_design 3. website ......
How I can remove words with less than N characters from tags? Is it possible with a regex?
For example if N=4 so "web" will be removed from my example and the rest remains.
I will give a solution to do this without changing your design at the bottom of this answer,
but I really think you should fix the design, here is an example on how to do that.
It starts from a table called "mytable" that has your "tag" column with all the data,
then it creates a detail table and populates it with the splitted values from your tag column
and then it is very easy to do what you want to do
create table tags (id int identity primary key, mytable_id int, tag varchar(100))
insert into tags (mytable_id, tag)
select t.id,
value
from mytable t
cross apply string_split(t.tag, ' ')
alter table mytable drop column tag
See a complete example in this dbfiddle
EDIT
if you need to show it again as if it where in one table, you can use string_agg like this
select m.id,
m.name,
( select string_agg(t.tag, ' ')
from tags t
where t.mytable_id = m.id
) as tags
from mytable m
You can see this at work in this dbfiddle
EDIT 2
And if you really want to stick to your design, here is how you can remove the words from your tag column
But I recommend not doing this, as you can see in the examples above it is not so hard to fix the design and create a new table to hold the tags.
update m
set m.tag =
( select string_agg(value, ' ')
from mytable t
cross apply string_split(m.tag, ' ')
where len(value) > 3
and t.id = m.id
)
from mytable m
Look at this dbfiddle to see it in action

Count the occurences of all individual values in a multivalued field in SQL Server

Features Impressive
A,B,C
D,C
A,D
B,C,D
This is a column in my database that contains multiple values that comes from combobox.
I want to count the number of occurrences of each value in this column so that I can generate a bar chart out of this reflecting how many people liked the specific features.
Output I want is
A- 2
B- 2
C- 3
D- 3
Please help me with this SQL query.
You have a very poor design. You should be storing individual values in a separate row in a junction table -- one row per whatever and value.
Given the data structure, here is a method to do what you want -- assuming that you have a lit of allowed values:
select av.feature, count(t.feature)
from AllowedValues av left join
tables t
on ',' + av.feature + ',' like '%,' + t.features + ',%'
group by av.feature;
If you don't have an explicit list of features, you can create one using a CTE, something like:
with AllowedValues as
select 'A' as feature union all
. . .
)
The performance of this query will be lousy. And, there is really no way to make it better without fixing the data structure.
So, I repeat. You should fix the data structure and use a junction table instead of storing a list as a string. In SQL, tables are for storing lists. Strings are for, well, storing strings.
As mentioned by others really this is poor design you should never store comma separated values in a single column.
Use a Split Function to split the comma separated values into individual rows then count the individual rows. Something like this.
;With CTE as
(
SELECT Split.a.value('.', 'VARCHAR(100)') SP_COL
FROM (SELECT Cast ('<M>' + Replace(feature, ',', '</M><M>') + '</M>' AS XML) AS Data
FROM [table]) AS A
CROSS APPLY Data.nodes ('/M') AS Split(a)
)
Select SP_COL,COUNT(1) as [COUNT]
FROM CTE
Group By SP_COL

Dynamically replace data in a oracle field with SQL

I have a varchar column test_data with data in csv format in a table temp_table1.
Example Data >
,1,2,3,
,14,18,
,3,4,
for each numerical there is a mapping string like 1="ABC",2="XYX" , 3="PQR" on another
database mapping table temp_table2
Is there any way to display the data by replacing each numerical with its mapping using a
single sql query??
eg: **,1,2,3**, as **ABC,XYZ,PQR**
I have tried using decode,regexp_replace but cannot find the solution.
Database : Oracle 11g.
There is a way to do this, albeit a bit yucky. You really should use a junction table and fix the database structure, if you have any control over this.
The method is to expand the data using an inefficient join and then use listagg() to bring the results back together. The result is something like this:
select td.id, listagg(tt.val, ',') within group (order by td.id)
from test_data td left join
temp_table2 tt
on td.col like '%,' || tt.col || '%,'
group by td.id;

Check if a list of items already exists in a SQL database

I want to create a group of users only if the same group does not exist already in the database.
I have a GroupUser table with three columns: a primary key, a GroupId, and a UserId. A group of users is described as several lines in this table sharing a same GroupId.
Given a list of UserId, I would like to find a matching GroupId, if it exists.
What is the most efficient way to do that in SQL?
Let say your UserId list is stored in a table called 'MyUserIDList', the following query will efficiently return the list of GroupId containing exactly your user list. (SQL Server Syntax)
Select GroupId
From (
Select GroupId
, count(*) as GroupMemberCount
, Sum(case when MyUserIDList.UserID is null then 0 else 1 End) as GroupMemberCountInMyList
from GroupUser
left outer join MyUserIDList on GroupUser.UserID=MyUserIDList.UserID
group by GroupId
) As MySubQuery
Where GroupMemberCount=GroupMemberCountInMyList
There are couple of ways of doing this. This answer is for sql server only (as you have not mentioned it in your tags)
Pass the list of userids in comma seperated to a stored procedure and in the SP create a dynamic query with this and use the EXEC command to execute the query. This link will guide you in this regard
Use a table-valued parameter in a SP. This is applicable to sql server 2008 and higher only.
The following link will help you get started.
http://www.codeproject.com/Articles/113458/TSQL-Passing-array-list-set-to-stored-procedure-MS
Hope this helps.
One other solution is that you convert the input list into a table. This can be done with various approaches. Unions, temporary tables and others. A neat solution combines the answer of
user1461607 for another question here on SO, using a comma-separated string.
WITH split(word, csv) AS (
-- 'initial query' (see SQLite docs linked above)
SELECT
'', -- place holder for each word we are looking for
'Auto,A,1234444,' -- items you are looking for
-- make sure the list ends with a comma !!
UNION ALL SELECT
substr(csv, 0, instr(csv, ',')), -- each word contains text up to next ','
substr(csv, instr(csv, ',') + 1) -- next recursion parses csv after this ','
FROM split -- recurse
WHERE csv != '' -- break recursion once no more csv words exist
) SELECT word, exisiting_data
FROM split s
-- now join the key you want to check for existence!
-- for demonstration purpose, I use an outer join
LEFT OUTER JOIN (select 'A' as exisiting_data) as t on t.exisiting_data = s.word
WHERE s.word != '' -- make sure we clamp the empty strings from the split function
;
Results in:
Auto,null
A,A
1234444,null

How do I return rows if concatenated value is within another set of values?

This may be a dumb question, but I am trying to concatenate values from two columns and then return rows where those concatenated values are in another set.
My question is, what is the best method to do this? I've done this in the past using an IN statement, but if I have a lot of values this time around.
Would I be better off creating a new table with my comparison values and get my results using some kind of relationship statement? Something like that below?
SELECT Users.ID + Users.SubID AS UniqueID, TempVals.ID
FROM Users, TempVals
WHERE Users.ID + Users.SubID = TempVals.ID
Thanks!
What you have should work fine assuming it's MySQL and the data types of the columns being concatenated are strings/character-types - no worries, you should be able to cast them.
Another way:
SELECT DISTINCT U.ID + U.SubID AS UniqueID
FROM Users as U
WHERE (U.ID + U.SubID) IN (
SELECT DISTINCT T.ID
FROM TempVals as T
)
Also, the type of database will determine the method of concatenation:
SQL Server: +
Oracle: CONCAT()
MySQL: CONCAT()
Reference: Using IN Statement - SQL