First character replace in SQL Server - sql-server-2016

I have a question about SQL Server. How to replace only 1st character value when same character have multiple times?
CREATE TABLE [dbo].[productdetails]
(
[pid] [int] NULL,
[productName] [varchar](100) NULL
)
INSERT INTO [dbo].[productdetails] ([pid], [productName])
VALUES (1, N'cinphol')
INSERT INTO [dbo].[productdetails] ([pid], [productName])
VALUES (2, N'apple')
INSERT INTO [dbo].[productdetails] ([pid], [productName])
VALUES (3, N'ppens')
INSERT INTO [dbo].[productdetails] ([pid], [productName])
VALUES (4, N'penrpos')
GO
Based on this data, I want output like this:
pid | productname
----+------------
1 | cinZhol
2 | azple
3 | zpens
4 | zenrpos
My query:
select
pid, replace(productname, 'p', 'z') productname
from
productdetails
This query is not returning the expected results.
Could you please tell me how to achieve this task in SQL Server ?

select
pid,
replace(left(productname, 1), 'p', 'z') +
substring(productname, 2, len(productname)) productname
from
productdetails

Related

SQL recursion on a self-referencing table to obtain specific order

I have a table as below:
Id
LinkSlug
ParentPageId
Order
1
home
0
2
page2
1
3
page3
2
4
page11
1
0
5
page12
1
1
6
page13
1
2
7
page21
2
0
8
page22
2
1
9
page121
5
0
10
page122
5
1
11
page123
5
2
I'm sure you can already see the pattern - each Page can have any number of "SubPages" defined by the ParentPageId
I've been trying to get a query that can produce the following ordered output (without using the LinkSlug alphabetical ordering because they can be anything):
Id
LinkSlug
ParentPageId
Order
1
home
0
4
page11
1
0
5
page12
1
1
9
page121
5
0
10
page122
5
1
11
page123
5
2
6
page13
1
2
2
page2
1
7
page21
2
0
8
page22
2
1
3
page3
2
I tried doing some self-joins and grouping but ended up with only one level of recursion so it was no good for the 3rd and potentially nth degree sub pages, and then also tried using a CTE as I understand they're good for recursive queries but somehow ended up producing the same table I started with and am now at a loss!
The more I try the worse it gets - I know I need to effectively select top levels (with null ParentPageId) ordered by [Order], then inject wherever there's sub pages ordering by [Order], and repeat until there are no children left - but no idea how to do this in SQL.
View on DB Fiddle
And here's the fiddle script just in case:
CREATE TABLE [Pages](
[Id] [int] IDENTITY(1,1) NOT NULL,
[LinkSlug] [nvarchar](450) NOT NULL,
[ParentPageId] [int] NULL,
[Order] [int] NOT NULL
);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (1, 'home', NULL, 0);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (2, 'page2', NULL, 1);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (3, 'page3', NULL, 2);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (4, 'page11', 1, 0);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (5, 'page12', 1, 1);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (6, 'page13', 1, 2);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (7, 'page21', 2, 0);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (8, 'page22', 2, 1);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (9, 'page121', 5, 0);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (10, 'page122', 5, 1);
INSERT into [Pages] ([Id], [LinkSlug], [ParentPageId], [Order]) VALUES (11, 'page123', 5, 2);
You would need a recursive CTE to build the hierarchy and maintain the sequence
Example
with cte1 as (
Select [Id]
,[LinkSlug]
,[ParentPageId]
,[Order]
,Seq = cast(10000+Row_Number() over (Order by [Order]) as varchar(500))
From pages
Where [ParentPageId] is null
Union All
Select cte2.[Id]
,cte2.[LinkSlug]
,cte2.[ParentPageId]
,cte2.[Order]
,Seq = cast(concat(cte1.Seq,'.',10000+Row_Number() over (Order by cte2.[Order])) as varchar(500))
From pages cte2
Join cte1 on cte2.[ParentPageId] = cte1.[Id])
Select *
From cte1
Order By Seq
Results
You can try this:
WITH cte_org (n, id,
LinkSlug,
ParentPageId) AS (
SELECT
CAST([order] as CHAR(200)),
id,
LinkSlug,
ParentPageId
FROM
pages
WHERE ParentPageId IS NULL
UNION ALL
SELECT
o.n || '_' || e.[order],
e.id,
e.LinkSlug,
e.ParentPageId
FROM
pages e
INNER JOIN cte_org o
ON o.id = e.ParentPageId)
SELECT * FROM cte_org order by n;
Note: that in MS SQL you need to use concat instead of ||; in MySQL - +

SQL Rollup Hierarchy Closest

I have the following scenario. As you could see Levels (1) – ItemNumber (NULL) is the incoming number, which all the ones listed below are associated to the main one.
Ultimately, what I want to do is only get the following rows
Lines 2 and 4,5,6
Since row 2 doesn’t have any children rows and USDAFoodItemID is not null
And 4,5,6 The parent row 3 does have children, and since row 3 is null,
The children 4,5,6 will be spit out.
If Line 1 was populated with USDAFoodItemID then it would only spit out line 1.
Sorry for my English, I am still working on it. But help is universal, and I would appreciate any help I could get.
Sorry, here is the code to produce the table. I am using MS SQL
DECLARE #HoldTable TABLE
(
Levels INT,
ItemNumber INT,
IngredientNumber INT,
NutritionalLoss FLOAT,
StandardAmountInGrams FLOAT,
SequenceNumber INT,
USDAFoodItemID NVARCHAR(5)
)
INSERT INTO #HoldTable VALUES (1, NULL, 1174258, 1.0000 ,113.3980925 ,1, NULL)
INSERT INTO #HoldTable VALUES (2, 1174258, 1174252 ,1.0000, 113.3980925, 1, 09096)
INSERT INTO #HoldTable VALUES (3, 1174252, 1006967, 1.0000, 56.69904625, 1, 01297)
INSERT INTO #HoldTable VALUES (3, 1174252, 1174251, 1.0000 ,56.69904625, 1, NULL)
INSERT INTO #HoldTable VALUES (4, 1174251, 1007555 ,1.0000 ,1.41747615625, 1 ,12078)
INSERT INTO #HoldTable VALUES (4, 1174251, 1010210, 1.0000, 26.93204696875, 1 ,NULL)
INSERT INTO #HoldTable VALUES (4, 1174251, 1010984, 1.0000, 28.349523125, 1 ,NULL)
SELECT * FROM #HoldTable
Thank you

Sql Select using CTE to order a recursive data

Please i want a solution for this problem using CTE in SQL Server
Example for the situation
Equation 0 = 0.25*Equation 1
Equation 1 = Equation 2 + Equation 3 + 0.5*Equation 5
Equation 2 = 15 + 40
Equation 3 = Equation 6 + Equation 7
Equation 4 = 10
Equation 5 = 10 + Equation 4
Equation 6 = 10 +5
Equation 7 = Equation 5 + Equation 2
The structure of the tables is
The Element Table
ID | Name
-------|--------------
0 | Equation 0
1 | Equation 1
2 | Equation 2
3 | Equation 3
4 | Equation 4
5 | Equation 5
6 | Equation 6
7 | Equation 7
---------------------
the table holds all items of each equation
The equation Table
FK | Item | Type
-------|-----------|------------------
0 | 0.25 | constant
0 | * | Operator
0 | 1 | Element
1 | 2 | Element
1 | + | Operator
1 | 3 | Element
1 | + | Operator
1 | 0.5 | constant
1 | * | Operator
1 | 5 | Element
2 | 15 | constant
2 | + | Operator
2 | 40 | constant
… | |
… | |
… etc | |
------------------------------------
if the type is element this means it is an element item
is there any sql statement result to the correct order that i must use to calculate these equations one by one without using recursive functions because it is limited in SQL
the alternative is to calculate the last equation without any requirements then calculate the upper ones as when i need an equation i find it calculated already without recursing the equations
i need the sql select statement to produce the following order
Equation 2
Equation 6
Equation 4
Equation 5
Equation 7
Equation 3
Equation 1
Equation 0
i ordered them by eye because it is simple example
is there any select statement is used to do so
or the user must order them manually ???
... Update
1. with a fully working test scenario
The Script to create tables
/****** Object: Table [dbo].[Element] Script Date: 26/03/2017 11:10:10 م ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Element](
[Id] [int] NOT NULL,
[Name] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_Element] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
/****** Object: Table [dbo].[Equation] Script Date: 26/03/2017 11:10:10 م ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Equation](
[fk] [int] NOT NULL,
[Item] [nvarchar](50) NOT NULL,
[Type] [nvarchar](50) NOT NULL
) ON [PRIMARY]
GO
INSERT [dbo].[Element] ([Id], [Name]) VALUES (0, N'Equation 0')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (1, N'Equation 1')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (2, N'Equation 2')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (3, N'Equation 3')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (4, N'Equation 4')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (5, N'Equation 5')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (6, N'Equation 6')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (7, N'Equation 7')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (0, N'0.25', N'constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (0, N'*', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (0, N'1', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'2', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'3', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'0.5', N'constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'*', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'5', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (2, N'15', N'constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (2, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (2, N'40', N'constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (3, N'6', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (3, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (3, N'7', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (4, N'10', N'Constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (5, N'10', N'Constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (5, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (5, N'4', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (6, N'10', N'Constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (6, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (6, N'5', N'Constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (7, N'5', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (7, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (7, N'2', N'Element')
*
#Gordon Linoff
... Thanks a lot for your care but i found some errors using the provided script that i cant solve as it is the first time for me to use CTE
The second script gives me some errors that i cant solve
the first script gives me errors as well that i cant solve
You can try it like this:
WITH Related AS
(
SELECT *
FROM Equation AS eq
LEFT JOIN Element AS e ON eq.[Type]='Element' AND eq.Item=CAST(e.Id AS VARCHAR(10))
WHERE eq.[Type]='Element'
)
,Dependecies AS
(
SELECT e.*
,ISNULL(r.Name,'') AS DepName
FROM Element AS e
LEFT JOIN Related AS r ON e.Id=r.fk
)
,recCTE AS
(
SELECT 1 AS lvl,d.Id,d.Name,d.DepName
FROM Dependecies AS d
WHERE d.Name NOT IN(SELECT x.DepName FROM Dependecies AS x)
UNION ALL
SELECT r.lvl+1,d.Id,d.Name,d.DepName
FROM recCTE AS r
INNER JOIN Dependecies AS d ON r.DepName=d.Name
)
,Ranked AS
(
SELECT Name
,DENSE_RANK() OVER(ORDER BY CASE WHEN DepName='' THEN 1000 ELSE lvl END DESC) AS Rnk
FROM recCTE
)
SELECT Name,MIN(Rnk) AS Rnk
FROM Ranked
GROUP BY Name
ORDER BY Min(Rnk)
The result
Equation 2 1
Equation 4 1
Equation 6 1
Equation 5 2
Equation 7 3
Equation 3 4
Equation 1 5
Equation 0 6
Explanation
There is a list of CTEs:
The first CTE will bind the Elements to Equation rows, where the type is Element.
The second will list all Elements with their dependencies
The third CTE is a recursive CTE, starting with the element without any dependecies, working down the dependency path
The next CTE uses DENSE_RANK() OVER() to get the calls ordered
The final SELECT returns each element and the earliest moment it is needed.
Oh, it would be swell if we could express this as:
with cte as (
select e.fk, 1 as lev
from equation e
group by e.fk
having sum(case when type = 'Element' then 1 else 0 end) = 0
union all
select e.fk, max(cte.lev) + 1
from equation e left join
cte
on e.fk = cte.fk
group by e.fk
having count(*) = count(cte.fk)
)
But that is not possible. So, we have to think in terms of string manipulation (I think). This results in putting the dependencies in a string and repeatedly chopping elements off of the string. If I have this right:
with eq as (
select e.fk,
stuff( (select ',' + e2.item
from equation e2
where e2.fk = e.fk and e2.type = 'Element'
order by e2.item
for xml path ('')
), 1, 1, '') as elements
from (select distinct e.fk from equation e) e
)
select e.fk, '' as elements_found, 1 as lev
from eq
where elements = ''
union all
select eq.fk, substring(elements_found, charindex(',', elements_found + ',') + 1), 2 as lev
from eq join
cte
on cte.elements_found like eq.fk + ',%' and eq.fk = cte.fk
where eq.type = 'Element'
)
select cte.fk, max(lev)
from cte
group by cte.fk
order by max(lev);

Add not relevant column to group by script

This is my sample table and values:
CREATE TABLE [dbo].[Test]
(
[Id] BIGINT NOT NULL DEFAULT(0),
[VId] BIGINT NOT NULL DEFAULT(0),
[Level] INT NOT NULL DEFAULT(0)
);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (100, 1, 1);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (101, 1, 2);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (102, 1, 3);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (103, 2, 1);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (104, 3, 1);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (105, 3, 2);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (106, 4, 1);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (107, 4, 2);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (108, 4, 3);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (109, 4, 4);
So at now I use this script:
SELECT
[T].[VId], MAX ([T].[Level]) AS [MaxLevel]
FROM
[dbo].[Test] AS [T]
GROUP BY
[T].[VId];
And it returns:
VId MaxLevel
1 3
2 1
3 2
4 4
But I need Id column also and I can't add it to Group by script, I need the following values:
VId MaxLevel Id
1 3 102
2 1 103
3 2 105
4 4 109
What is your suggestion?
Also The following values is enough The Id's With Max(Level) in any VId :
Id
102
103
105
109
A 2008 take on the question, since that's what you're working with:
declare #Test table
(
[Id] BIGINT NOT NULL DEFAULT(0),
[VId] BIGINT NOT NULL DEFAULT(0),
[Level] INT NOT NULL DEFAULT(0)
);
INSERT INTO #Test ([Id], [VId], [Level])
VALUES (100, 1, 1),(101, 1, 2),(102, 1, 3),(103, 2, 1),(104, 3, 1),
(105, 3, 2),(106, 4, 1),(107, 4, 2),(108, 4, 3),(109, 4, 4);
;With Numbered as (
select *,
RANK() OVER (PARTITION BY VId ORDER BY [Level] desc) as rn
from #Test)
select VId,Level,Id from Numbered where rn=1
Note that (as with the other solutions) this will output multiple rows per VId if there are two rows with the same maximum level. If you don't want that, switch RANK() to ROW_NUMBER() and an arbitrary one will win - or if you want a specific winner in the case of a tie, add that condition into the ORDER BY of the window function.
Use joining with the same table by VId column
something like this:
SELECT [T].[VId], [T].[MaxLevel], [T1].[Id]
FROM [dbo].[Test] AS [T1] JOIN
(SELECT [T].[VId], MAX ([T].[Level]) AS [MaxLevel]
FROM [dbo].[Test] AS [T]
GROUP BY [T].[VId]) AS [T]
ON [T1].[VId] = [T].[VId]
AND [T1].[Level] = [T].[MaxLevel]
ORDER BY [T].[VId];
the result will be:
VId MaxLevel Id
1 3 102
2 1 103
3 2 105
4 4 109
Use this:
WITH LastLevels AS
(
SELECT
[T].[VId] AS [VID],
MAX ([T].[Level]) AS [MaxLevel]
FROM [dbo].[Test] AS [T]
GROUP BY [T].[VId]
)
SELECT [LastLevels].[VID],[LastLevels].[MaxLevel], [Te].[Id]
FROM [dbo].[Test] AS [Te]
INNER JOIN [LastLevels]
ON [LastLevels].[VID]=[Te].[VId]
AND [LastLevels].[MaxLevel]=[Te].[Level]
ORDER BY [LastLevels].[VID];
SELECT ID, [VId], [MaxLevel] From
(
SELECT
[T].[VId], MAX ([T].[Level]) AS [MaxLevel]
FROM
[dbo].[Test] AS [T]
GROUP BY
[T].[VId]
)K
INNER JOIN [Test] T on T.[VId] = K.[VId] and T.[Level] = K.MaxLevel

Help with a SQL Query

My tables:
suggestions:
suggestion_id|title|description|user_id|status|created_time
suggestion_comments:
scomment_id|text|user_id|suggestion_id
suggestion_votes:
user_id|suggestion_id|value
Where value is the number of points assigned to a vote.
I'd like to be able to SELECT:
suggestion_id, title, the number of comments and the SUM of values for that suggestion.
sorted by SUM of values. LIMIT 30
Any ideas?
You may want to try using sub queries, as follows:
SELECT s.suggestion_id,
(
SELECT COUNT(*)
FROM suggestion_comments sc
WHERE sc.suggestion_id = s.suggestion_id
) num_of_comments,
(
SELECT SUM(sv.value)
FROM suggestion_votes sv
WHERE sv.suggestion_id = s.suggestion_id
) sum_of_values
FROM suggestions s;
Test case:
CREATE TABLE suggestions (suggestion_id int);
CREATE TABLE suggestion_comments (scomment_id int, suggestion_id int);
CREATE TABLE suggestion_votes (user_id int, suggestion_id int, value int);
INSERT INTO suggestions VALUES (1);
INSERT INTO suggestions VALUES (2);
INSERT INTO suggestions VALUES (3);
INSERT INTO suggestion_comments VALUES (1, 1);
INSERT INTO suggestion_comments VALUES (2, 1);
INSERT INTO suggestion_comments VALUES (3, 2);
INSERT INTO suggestion_comments VALUES (4, 2);
INSERT INTO suggestion_comments VALUES (5, 2);
INSERT INTO suggestion_comments VALUES (6, 3);
INSERT INTO suggestion_votes VALUES (1, 1, 3);
INSERT INTO suggestion_votes VALUES (2, 1, 5);
INSERT INTO suggestion_votes VALUES (3, 1, 1);
INSERT INTO suggestion_votes VALUES (1, 2, 4);
INSERT INTO suggestion_votes VALUES (2, 2, 2);
INSERT INTO suggestion_votes VALUES (1, 3, 5);
Result:
+---------------+-----------------+---------------+
| suggestion_id | num_of_comments | sum_of_values |
+---------------+-----------------+---------------+
| 1 | 2 | 9 |
| 2 | 3 | 6 |
| 3 | 1 | 5 |
+---------------+-----------------+---------------+
3 rows in set (0.00 sec)
UPDATE: #Naktibalda's solution is an alternative solution that avoids sub queries.
I was typing the same query as potatopeelings.
But there is an issue:
Resultset after joins contains M*N rows (M-number of comments, N-number of votes, not less than 1) for each suggestion.
To avoid that you have to count distinct comment ids and divide a sum of votes by number of comments.
SELECT
s.*,
COUNT(DISTINCT c.scommentid) AS comment_count,
SUM(v.value)/GREATEST(COUNT(DISTINCT c.scommentid), 1) AS total_votes
FROM suggestions AS s
LEFT JOIN suggestion_comments AS c ON s.suggestion_id = c.suggestion_id
LEFT JOIN suggestion_votes AS v ON s.suggestion_id = v.suggestion_id
GROUP BY s.suggestion_id
ORDER BY total_votes DESC
LIMIT 30