I'm having two tables namely ds_message and ds_params, the first table contains the template and the second tables contains the key value pair
Table Structure: ds_message
_____________________________________________
id template
_____________________________________________
1 'Dear {a}, the price of {b} is {c}'
2 'Dear {i}, you selected the product {j}'
Schema:
CREATE TABLE `ds_message` (
`id` int NOT NULL,
`template` varchar(500) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='';
ALTER TABLE `ds_message`
ADD PRIMARY KEY (`id`);
INSERT INTO `ds_message` (`id`, `template`) VALUES
(1, 'Dear {a}, the price of {b} is {c}');
INSERT INTO `ds_message` (`id`, `template`) VALUES
(2, 'Dear {i}, you selected the product {j}');
Table Structure: ds_params
_________________________________________________
id message_id json_key json_value
_________________________________________________
1 1 a John
2 1 b bat
3 1 c $10
4 2 i Emma
5 2 j Jam
Schema:
CREATE TABLE `ds_params` (
`id` int NOT NULL,
`message_id` int NOT NULL,
`json_key` varchar(500) NOT NULL,
`json_value` varchar(500) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='';
ALTER TABLE `ds_params`
ADD PRIMARY KEY (`id`);
INSERT INTO `ds_params` (`id`, `message_id`, `json_key`, `json_value`) VALUES
(1, 1, 'a', 'John');
INSERT INTO `ds_params` (`id`, `message_id`, `json_key`, `json_value`) VALUES
(2, 1, 'b', 'bat');
INSERT INTO `ds_params` (`id`, `message_id`, `json_key`, `json_value`) VALUES
(3, 1, 'c', '$10');
INSERT INTO `ds_params` (`id`, `message_id`, `json_key`, `json_value`) VALUES
(4, 2, 'i', 'Emma');
INSERT INTO `ds_params` (`id`, `message_id`, `json_key`, `json_value`) VALUES
(5, 2, 'j', 'Jam');
I need to replace the keys (for example {a} => John) in the ds_message table.
I tried the following code,
UPDATE ds_message AS t
INNER JOIN ds_params m ON m.message_id = t.id
SET t.template = REPLACE(t.template, CONCAT('{', m.json_key , '}'), m.json_value);
Once I executed the code I'm getting the output like this, only the first key gets replaced, remaining keys not get update.
_____________________________________________
id template
_____________________________________________
1 Dear John, the price of {b} is {c}
2 Dear Emma, you selected the product {j}
Kindly assist me how to do this.
We have 2 options.
First is using while loop.
SET #n = 0;
SELECT COUNT(*) FROM ds_params INTO #n;
SET #i=0;
WHILE #i<#n DO
UPDATE ds_message AS t
INNER JOIN ds_params m ON m.message_id = t.id AND m.id = #i
SET t.template = REPLACE(t.template, CONCAT('{', m.json_key , '}'), m.json_value)
SET #i = #i + 1;
END WHILE;
2nd Option is this. If you have a fix json_key
UPDATE ds_message AS t
LEFT JOIN ds_params a ON a.message_id = t.id and a.json_key='a'
LEFT JOIN ds_params b ON b.message_id = t.id and b.json_key='b'
LEFT JOIN ds_params c ON c.message_id = t.id and c.json_key='c'
LEFT JOIN ds_params i ON i.message_id = t.id and i.json_key='i'
LEFT JOIN ds_params j ON j.message_id = t.id and j.json_key='j'
SET t.template = REPLACE(REPLACE(REPLACE(
REPLACE(REPLACE(t.template, CONCAT('{', IFNULL(a.json_key, '') , '}')
, IFNULL(a.json_value, '')),
CONCAT('{', IFNULL(b.json_key, '') , '}'), IFNULL(b.json_value, '')),
CONCAT('{', IFNULL(c.json_key, '') , '}'), IFNULL(c.json_value, '')),
CONCAT('{', IFNULL(i.json_key, '') , '}') ,IFNULL(i.json_value, '')),
CONCAT('{', IFNULL(j.json_key, '') , '}') ,IFNULL(j.json_value, ''));
You need to perform loop in this update. Since there is no fix key value pair so it is better to find the max key value pair to perform loop.
After that loop through each record using CURSOR to perform the update to replace your key with corresponding value. Since you already find out the max value of key pair so it will perform only till the max limit of loop for your query.
For reference you may find this link for details on CURSOR.
DECLARE a, b VARCHAR(10);
DECLARE cur1 CURSOR FOR SELECT DISTINCT json_key,json_value
FROM ds_params.t1;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO a, b;
IF done THEN
LEAVE read_loop;
END IF;
UPDATE ds_message AS t
INNER JOIN ds_params m ON m.message_id = t.id
SET t.template = REPLACE(t.template, CONCAT('{', m.json_key , '}'), m.json_value)
WHERE M.JSON_KEY = b ;
END LOOP;
CLOSE cur1;
I am not sure about syntax but you may get the idea of implementing the same. If anything in syntax is not correct then kindly update the same.
Related
I am trying to create a procedure that will update all fruits status if a fruit has at least one critical attribute.
For example i have an apple,banana and an orange with many attributes. One of the attributes of apple, orange marked as "Yes" on critical. in that case with a single call of the procedure apple and orange will have status id pointing on "bad", and banana as "good".
create table `status` (
s_id int,
s_stat enum ("Bad", "Good", "Rotten"),
primary key (s_id)
) ENGINE = InnoDB;
create table fruits (
f_id int,
f_name varchar(10),
f_status int,
primary key (f_id),
foreign key (f_status) references `status`(s_id)
on update cascade
) ENGINE = InnoDB;
create table attributes (
a_id int,
a_description varChar(25),
a_critital enum ("Yes", "No"),
primary key(a_id)
) ENGINE = InnoDB;
create table fruits_attributes (
fa_f_id int,
fa_a_id int,
primary key(fa_f_id, fa_a_id),
foreign key (fa_f_id) references fruits(f_id)
on update cascade,
foreign key (fa_a_id) references attributes(a_id)
on update cascade
) ENGINE = InnoDB;
insert into `status` values
(1, "Bad"),
(2, "Good"),
(3, "Rotten")
;
insert into fruits values
(1, "Apple", null),
(2, "Banana", null),
(3, "Orange", null)
;
insert into attributes values
(1, "Yellow mark", "No"),
(2, "Cuts", "Yes"),
(3, "Dirt", "No")
;
insert into fruits_attributes values
(1, 1),
(1, 2),
(1, 3),
(2, 3),
(3, 2)
;
So you are prioritising "Bad" over "Good". For example, if one apple is "Good", another apple is "Bad", you would update it as "Bad". Let me know if this is not the case.
For MySQL 8.0 version, db<>fiddle
CREATE PROCEDURE updtfruit()
BEGIN
UPDATE fruits f
JOIN (
SELECT f_id, s_id, ROW_NUMBER() OVER(PARTITION BY f_id ORDER BY s_id) AS rn
FROM fruits_attributes fa
JOIN fruits f ON fa.fa_f_id = f.f_id
JOIN attributes a ON fa.fa_a_id = a.a_id
JOIN `status` s ON s.s_stat = CASE WHEN a.a_critital = "Yes" THEN "Bad"
WHEN a.a_critital = "No" THEN "Good"
END
) filter ON f.f_id = filter.f_id
SET f.f_status = filter.s_id
WHERE filter.rn = 1;
END
For MySQL older versions, db<>fiddle
CREATE PROCEDURE updtfruit2()
BEGIN
UPDATE fruits f
JOIN (
SELECT f_id, MIN(s_id) AS s_id
FROM fruits_attributes fa
JOIN fruits f ON fa.fa_f_id = f.f_id
JOIN attributes a ON fa.fa_a_id = a.a_id
JOIN `status` s ON s.s_stat = CASE WHEN a.a_critital = "Yes" THEN "Bad"
WHEN a.a_critital = "No" THEN "Good"
END
GROUP BY f_id
) filter ON f.f_id = filter.f_id
SET f.f_status = filter.s_id;
END
I need to make trigger to increase the 2nd digit when the new value found to be a duplicate.
For Instance, I have a unique filed with 10 digits value. I want when someone insert same number it increase the second left digit like 0100012345. How I can do that? Thank you.
FirstName LastName Code
Houssam Salim 0100012345 to be 0200012345
Try this
I have found a solution with instead off trigger
'/*
CREATE TABLE [Employee1]
(
[id] VARCHAR(20) PRIMARY KEY,
[name] VARCHAR(50)
)
CREATE TRIGGER AutoIncrement_Trigger
ON [Employee1]
instead OF INSERT
AS
BEGIN
DECLARE #ch CHAR
DECLARE #num INT
IF EXISTS (SELECT 1
FROM Employee1 e
JOIN inserted i
ON i.id = e.id)
BEGIN
SET #num=(SELECT max(CONVERT(INT, substring(e.id, 1, 2))) + 1
FROM employee1 e
JOIN inserted i
ON substring(e.id, 3, len(e.id)) = substring(i.id, 3, len(i.id)))
INSERT INTO [Employee1]
(id,
name)
SELECT '0' + CONVERT(VARCHAR(10), #num)
+ substring(i.id, 3, len(i.id)),
e.name
FROM Employee1 e
JOIN inserted i
ON i.id = e.id
END
ELSE
BEGIN
INSERT INTO [Employee1]
(id,
name)
SELECT inserted.id,
inserted.name
FROM inserted
END
END
*/
INSERT INTO [Employee1]
VALUES ('0100012345',
'John')
SELECT *
FROM [Employee1]
INSERT INTO [Employee1]
VALUES ('0100012345',
'John')
SELECT *
FROM [Employee1]
'
I am trying to construct a query that will allow me to "filter" on pairs of columns for particular criteria. I need to be able to construct multiple filters for the same given pair. The end result should only return instances that have data for the case where all filters are applied.
I constructed a trivial example demonstrating what I would like to be able to do.
Using the follow table definition:
DROP TABLE IF EXISTS foo;
CREATE TEMPORARY TABLE `foo` (
`ID` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`Index` INT UNSIGNED NOT NULL,
`Header` VARCHAR(50) NOT NULL,
`Value` VARCHAR(255) NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE INDEX `ID_UNIQUE` (`ID` ASC));
INSERT INTO `foo` (`Index`, `Header`, `Value`)
VALUES
(0, 'Header_1', 'a'),
(0, 'Header_2', 'b'),
(1, 'Header_1', 'a'),
(1, 'Header_2', 'c');
I would like a query that would return the following, given that you are looking for the case where 'Header_1' == 'a' and 'header_2' == 'b':
Index | Header | Value
------------------------
0 | Header_1 | a
0 | Header_2 | b
My current attempt is as follows:
SELECT `Index`, `Header`, `Value` FROM `foo`
WHERE (
(`Header` = 'Header_1') AND (`Value` = 'a')
OR (
(`Header` = 'Header_2') AND (`Value` = 'b')
)
)
GROUP BY `Header`, `Value`
HAVING COUNT(DISTINCT `Index`) = 2
ORDER BY `Index`, `Header`;
That code returns the following:
Index | Header | Value
------------------------
0 | Header_1 | a
I am missing one of my return rows. How can I restructure the query to return all of the matching rows?
Note that I declared the table as a temporary table. This is important, as I am working with temporary tables, and they have special restrictions to keep in mind (namely not being able to open it more than once in the same statement).
Your query returns only header_1 because the clause:
HAVING COUNT(DISTINCT `Index`) = 2
is only correct for Header_1.
Header_2 has count=1, therefore removed from the end result.
To get a clearer picture of what i say use:
SELECT `Index`, `Header`, `Value`, COUNT(DISTINCT `Index`) FROM `foo`
WHERE (
(`Header` = 'Header_1') AND (`Value` = 'a')
OR (
(`Header` = 'Header_2') AND (`Value` = 'b')
)
)
GROUP BY `Header`, `Value`
ORDER BY `Index`, `Header`;
and take a look at the last column.
I couldn't figure out how to do this with only the one temporary table. I'm not happy with this result, but at least it works.
DROP TABLE IF EXISTS `foo2`;
CREATE TEMPORARY TABLE `foo2` (
SELECT `Index` FROM `foo`
WHERE (
(`Header` = 'Header_1') AND (`Value` = 'a')
OR (
(`Header` = 'Header_2') AND (`Value` = 'b')
)
)
GROUP BY `Index`
HAVING COUNT(DISTINCT `Header`) = 2
);
SELECT DISTINCT t1.`Index`, t1.`Header`, t1.`Value` FROM `foo` t1
INNER JOIN `foo2` t2 ON t2.`Index` = t1.`Index`
ORDER BY t1.`Index`, t1.`Header`;
How about...
SELECT `index`
FROM foo
WHERE (header,value) IN (('header_1','a'))
OR (header,value) IN (('header_2','b'))
GROUP
BY `index`
HAVING COUNT(*) = 2;
I'm looking to see if this is even possible. I am constructing a view that needs to have a sub query. However, the sub query needs to have the same where clause as the main SQL statement.
I need to have this in a view, because I have to do a JOIN from another table, and a stored procedure, nor a table UDF will work in my case.
I've constructed the following example to show what I'm trying to do:
IF OBJECT_ID('tempdb..#TableA') IS NOT NULL BEGIN DROP TABLE #TableA END
IF OBJECT_ID('tempdb..#TableB') IS NOT NULL BEGIN DROP TABLE #TableB END
Create Table #TableA
(
Id INT IDENTITY(1, 1)
, ValueA VARCHAR(10)
)
Create Table #TableB
(
Id INT IDENTITY(1, 1)
, TableAID INT
, ValueB VARCHAR(10)
)
INSERT INTO #TableA VALUES ('Company A'), ('Company B')
INSERT INTO #TableB VALUES (1, '05001'), (1, '05002')
INSERT INTO #TableB VALUES (2, '04001'), (2, '04003')
SELECT
DISTINCT
A.ValueA
, STUFF((SELECT
', ' + B.ValueB
FROM
#TableB B
INNER JOIN #TableA A on A.Id = B.TableAID
WHERE
B.ValueB IN ('05001', '05002') --This needs to be part of the main where clause
FOR XML PATH ('')), 1, 1, '') as TBValue
FROM
#TableA A
INNER JOIN #TableB B on B.TableAID = A.Id
WHERE
B.ValueB IN ('05001', '05002') --This will be passed in as the where clause for the View
IF OBJECT_ID('tempdb..#TableA') IS NOT NULL BEGIN DROP TABLE #TableA END
IF OBJECT_ID('tempdb..#TableB') IS NOT NULL BEGIN DROP TABLE #TableB END
The output from the above example give us this:
ValueA TBValue
Company A 05001, 05002
I need to be able to get the sub query to use the same values as the main where clause, OR reconstruct the query to use the primary where clause somehow for the sub data.
You can not pass parameters into a view. They are not designed to accept them. I believe you need to use a Table-Valued (Inline-Table) Function in this case. This will allow you to pass in the values you want and get a 'table' back.
You should be able to use the same code you've already written for your view, with minor changes in the function. You will have to declare your incoming variables, and outgoing table value.
CREATE FUNCTION tvf_SomeFunction
(
-- Add the parameters for the function here
#Value1 varchar(10),
#Value2 varchar(10)
)
RETURNS TABLE
AS
RETURN
DECLARE #TableA TABLE
(
Id INT IDENTITY(1, 1)
, ValueA VARCHAR(10)
)
DECLARE #TableB TABLE
(
Id INT IDENTITY(1, 1)
, TableAID INT
, ValueB VARCHAR(10)
)
INSERT INTO #TableA VALUES ('Company A'), ('Company B')
--INSERT INTO #TableB VALUES (1, '05001'), (1, '05002')
--INSERT INTO #TableB VALUES (2, '04001'), (2, '04003')
SELECT
DISTINCT
A.ValueA
, STUFF((SELECT
', ' + B.ValueB
FROM
#TableB B
INNER JOIN #TableA A on A.Id = B.TableAID
WHERE
B.ValueB IN (#Value1, #Value2) --This needs to be part of the main where clause
FOR XML PATH ('')), 1, 1, '') as TBValue
FROM
#TableA A
INNER JOIN #TableB B on B.TableAID = A.Id
WHERE
B.ValueB IN (#Value1, #Value2) --This will be passed in as the where clause
)
GO
Your final SQL would be as simple as the following:
SELECT *
FROM tvf_SomeFunction('05001', '05002')
I need to list all the order done with every customer , So if a certain customer had passed 6 order then we need to list order1 | Order2| order3| ...
I have a table called Order where we have the Client Id , I am using SqlServer 2008 R2 , I have tried different approach but with no success , they run for ever and never gave a result :s , Here my lates try :
SELECT convert(varchar(1),isnull(user.Order.OrderId,'')) +' | '+ convert(varchar(1),isnull(Order_1.OrderId,'')) +' | '+convert(varchar(1),isnull(Order_2.OrderId,'')) +' | '+convert(varchar(1),isnull(Order_3.OrderId,'')) +' | '+convert(varchar(1),isnull(Order_4.OrderId,'')) +' | '+convert(varchar(1),isnull(Order_5.OrderId,'')) as OrderIdList,
user.client.kdnr
FROM user.Order
left outer JOIN user.Order AS Order_1 ON user.Order.clientnr = Order_1.clientnr AND Order_1.OrderId <> user.Order.OrderId and Order.orderDate < Order_1.orderDate
left outer JOIN user.Orderold AS Order_2 ON user.Order.clientnr = Order_2.clientnr AND Order_2.OrderId not in ( user.Order.OrderId , Order_1.OrderId ) and Order_1.orderDate < Order_2.orderDate
left outer JOIN user.Orderold AS Order_3 ON user.Order.clientnr = Order_3.clientnr AND Order_3.OrderId not in ( user.Order.OrderId , Order_1.OrderId, Order_2.OrderId ) and Order_1.orderDate < Order_2.orderDate
left outer JOIN user.Orderold AS Order_4 ON user.Order.clientnr = Order_4.clientnr AND Order_4.OrderId not in ( user.Order.OrderId , Order_1.OrderId, Order_2.OrderId, Order_3.OrderId ) and Order_2.orderDate < Order_3.orderDate
left outer JOIN user.Orderold AS Order_5 ON user.Order.clientnr = Order_5.clientnr AND Order_5.OrderId not in ( user.Order.OrderId , Order_1.OrderId, Order_2.OrderId, Order_3.OrderId, Order_4.OrderId ) and Order_3.orderDate < Order_4.orderDate
INNER JOIN user.client ON Order_1.clientnr = user.client.kdnr
group by client.kdnr ,user.client.name1, user.client.firstname, user.Order.OrderId, Order_1.OrderId,Order_1.Ordernr,Order_2.OrderId ,Order_3.OrderId,Order_4.OrderId,Order_5.OrderId `
Does any body have an dea how would I do that Correctly?
By using XML capabilities of SQL Server 2005 and above you can easily and efficiently generate comma separated values.
Try this (adjust according to your table and column names):
-- Sample tables
declare #Customer table
(
CustomerId int,
Name varchar(50)
)
declare #Order table
(
OrderId int,
CustomerId int
)
-- Sample data
insert into #Customer (CustomerId, Name) values (1, 'Alice')
insert into #Customer (CustomerId, Name) values (2, 'Mary')
insert into #Customer (CustomerId, Name) values (3, 'David')
insert into #Order (OrderId, CustomerId) values (1, 1)
insert into #Order (OrderId, CustomerId) values (2, 1)
insert into #Order (OrderId, CustomerId) values (3, 1)
insert into #Order (OrderId, CustomerId) values (4, 2)
insert into #Order (OrderId, CustomerId) values (5, 2)
insert into #Order (OrderId, CustomerId) values (6, 3)
----select * from #Customer
----select * from #Order
/* Actual Query that would add the OrderId from #Order table as a comma separated list against relevant Customer */
SELECT Customer.CustomerId as CustomerId, Customer.Name,
(
SELECT Convert(varchar(1), O.OrderId) + ','
FROM #Order AS O
WHERE O.CustomerId = Customer.CustomerId
ORDER BY O.OrderId
FOR XML PATH('')
) AS OrderList
FROM #Customer AS Customer
Well, i can't give you a complete answer, but i can tell you how to solve it. Try to use Common Table Expressions (http://msdn.microsoft.com/en-us/library/ms177410(v=sql.105).aspx).
With this you can join to your own resultset, where you make a recursive loop to solve this issue.
Hope it helps you