Copy hierarchical SQL Data in same Table with updated Values - php

I have a table "projects" and a table "tasks" with hierarchical data in my SQL Database. So the tasks have subtasks which are linked with a "parent"-column to its parentID. The Root-Task-Parent is 0.
There is also a column "project_id" which refers the task to a specific project in the Project-Table. What i want to do now is to copy a whole task with all subtasks and refer it to a new project.
So the SQL-Query would be
INSERT INTO tasks (text, date, parent, projectid)
SELECT text, date, parent, 89
FROM tasks WHERE projectid = 23
where 23 is the id of the old project and 89 is the project to which the data is added.
But the problem is that it keeps the parent value, so my root task is copied properly, but the subtasks still refer to the old tasks. How can i update the parentID as well so the whole tasks and subtasks refer to the new Root Task?
I want to use this in my PHP-Web-Application for a Project-Management-Tool, so that the User can simply choose a "Master-Template" to copy its structure to a new project.
Thank you for your help!
Edit:
#Strawberry: I use dhtmlxgantt to create and update task but i want to solve it with SQL queries. An example Table would look like this:
Screenshot of Database
So in this case i would like to duplicate "Project" to "Project 2" with a new projectID and matching subtasks with parentIDs

I assume that [text] field is unique for each project.
With this assumption, here is my query
--DROP TABLE [Tasks]
-- Create table
CREATE TABLE [dbo].[Tasks](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Text] [varchar](10) NOT NULL, -- Assume that [Text] field is unique for each project
[Name] [varchar](50) NOT NULL,
[ParentId] [bigint] NULL,
[ProjectId] [bigint] NOT NULL,
CONSTRAINT [PK_Tasks] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[Tasks] WITH CHECK ADD CONSTRAINT [FK_Tasks_Tasks] FOREIGN KEY([ParentId])
REFERENCES [dbo].[Tasks] ([Id])
GO
-- Remove all the data from the table and reseed the identity value
DELETE FROM [Tasks]
DBCC CHECKIDENT ('Tasks', RESEED, 1)
-- Sample Data population starts here...
INSERT INTO [Tasks] (text, Name, [ParentId], ProjectId)
SELECT 'A', 'A', null, 101 union ALL
SELECT 'B', 'B', null, 101 union ALL
SELECT 'C', 'C', null, 101
INSERT INTO [Tasks] (text, Name, [ParentId], ProjectId)
SELECT 'A1', 'A 1', (SELECT [Id] FROM [Tasks] WHERE [Text] = 'A'), 101 union ALL
SELECT 'A2', 'A 2', (SELECT [Id] FROM [Tasks] WHERE [Text] = 'A'), 101 union ALL
SELECT 'A3', 'A 3', (SELECT [Id] FROM [Tasks] WHERE [Text] = 'A'), 101 union ALL
SELECT 'A4', 'A 4', (SELECT [Id] FROM [Tasks] WHERE [Text] = 'A'), 101 union ALL
SELECT 'B1', 'B 1', (SELECT [Id] FROM [Tasks] WHERE [Text] = 'B'), 101 union ALL
SELECT 'B2', 'B 2', (SELECT [Id] FROM [Tasks] WHERE [Text] = 'B'), 101 union ALL
SELECT 'B3', 'B 3', (SELECT [Id] FROM [Tasks] WHERE [Text] = 'B'), 101 union ALL
SELECT 'C1', 'C 1', (SELECT [Id] FROM [Tasks] WHERE [Text] = 'C'), 101 union ALL
SELECT 'C2', 'C 2', (SELECT [Id] FROM [Tasks] WHERE [Text] = 'C'), 101 union ALL
SELECT 'C3', 'C 3', (SELECT [Id] FROM [Tasks] WHERE [Text] = 'C'), 101
INSERT INTO [Tasks] (text, Name, [ParentId], ProjectId)
SELECT 'A11', 'A 11', (SELECT [Id] FROM [Tasks] WHERE [Text] = 'A 1'), 101 union ALL
SELECT 'A41', 'A 41', (SELECT [Id] FROM [Tasks] WHERE [Text] = 'A 4'), 101
-- Sample Data population ends here...
GO
-- Copy all the data from project 101 and insert it as 102 with parent id as null
INSERT INTO [Tasks] (text, Name, [ParentId], ProjectId) -- other column names can be here...
SELECT text, Name, null, 102 -- Other column values can be here...
FROM [Tasks] where ProjectId = 101
-- Update the parent id using the text field
UPDATE A
SET A.[ParentId] = C.NewParentId
FROM [Tasks] A
INNER JOIN (SELECT Child.text, Parent.[Text] Parenttext
FROM [Tasks] Child
INNER JOIN [Tasks] Parent
ON Child.[ParentId] = Parent.[Id]
WHERE Child.ProjectId = 101
) B
ON A.[Text] = B.[Text]
LEFT JOIN (
SELECT [Id] NewParentId, [Text]
FROM [Tasks]
WHERE ProjectId = 102
) C
ON B.Parenttext = C.text
WHERE ProjectId = 102
SELECT * FROM [Tasks] WHERE ProjectId = 102 Order By [Text]
I hope this may help you

Related

How can I join a table to itself having it look like it's three tables?

Honestly, I don't know how to join a table to itself to solve this problem.
I have a table that stored it's record in the format below:
I want to query the table and display it's record in this format:
This is what I have tried so far
Select f.score as first_term, s.score as second_term, t.score as term_tetm from table f left join table s left join table t using (studentid) where studentid = 001 group by subject
You can get the result by grouping on the subject name, but then you will have to use an aggregate function. Here is an example:
CREATE TABLE #StudentGrades
(
[SUBJECT] VARCHAR(50),
[STUDENT_ID] VARCHAR(3),
[SCORE] INT,
[TERM] VARCHAR(50)
)
INSERT INTO #StudentGrades ([SUBJECT], [STUDENT_ID],[SCORE],[TERM])
VALUES ('English', '001', 50, '1st_Term'),
('Mathematics', '001', 40, '1st_Term'),
('French', '001', 60, '1st_Term'),
('English', '001', 60, '2nd_Term'),
('Mathematics', '001', 50, '2nd_Term'),
('French', '001', 50, '2nd_Term'),
('Computer', '001', 70, '2nd_Term'),
('English', '001', 65, '3rd_Term'),
('Mathematics', '001', 60, '3rd_Term'),
('French', '001', 70, '3rd_Term'),
('Computer', '001', 80, '3rd_Term')
SELECT [SUBJECT],
MAX(CASE WHEN [TERM] = '1st_Term' THEN [SCORE] END) AS '1ST_TERM',
MAX(CASE WHEN [TERM] = '2nd_Term' THEN [SCORE] END) AS '2ND_TERM',
MAX(CASE WHEN [TERM] = '3rd_Term' THEN [SCORE] END) AS '3RD_TERM'
FROM #StudentGrades
GROUP BY [SUBJECT]
ORDER BY [SUBJECT]
This is a simple solution but it works. Selecting student, subject and then sub-select for each of the terms. Finally, we DISTINCT it because there will be repetitions due to same subject on more than 1 term.
SELECT
DISTINCT
student_id,
`subject`,
(SELECT score FROM test AS t2 WHERE t2.student_id = t1.student_id AND t1.subject=t2.subject AND t2.term=1) AS term1,
(SELECT score FROM test AS t2 WHERE t2.student_id = t1.student_id AND t1.subject=t2.subject AND t2.term=2) AS term2,
(SELECT score FROM test AS t2 WHERE t2.student_id = t1.student_id AND t1.subject=t2.subject AND t2.term=3) AS term3
FROM
test AS t1

how to create structure with data repeated in a certain period

I need to return data from two tables this way
Array(
[0] => Array(
[Name] => lorem,
[Qty] => 2),
[1] => Array(
[Name] => ipsum,
[Qty] => 1),
[2] => Array(
[Name] => dolor,
[Qty] => 0)
)
PHP will only take care of getting the data, there will be no manipulation to organize it.
Two tables, one to record a certain event, the date and the id of a table related to the event. And the tables are like this:
tableA
id | date | tableB_id
1 2020-10-02 2
1 2020-10-19 2
1 2020-10-21 1
1 2020-11-2 3
1 2020-11-11 1
tableB
id | name
1 lorem
2 ipsum
3 dolor
And my SQL query
SELECT b.name as Name, a.created_at as created
FROM tableA b
INNER JOIN tableA a ON b.tableA_id = a.id WHERE MONTH(b.created_at) = '10' ORDER BY a.id;
which results in
Name | created
ipsum 2020-10-02
ipsum 2020-10-19
lorem 2020-10-21
You can Left Join TableA, but it irst need to have all the wanted rows as a subquery, to get also the 0 count
CREATE TABLE tableA (
`id` int,
`date` date,
`tableB_id` int
);
INSERT INTO tableA
(`id`, `date`, `tableB_id`)
VALUES
('1', '2020-10-02' , '2'),
('1' , '2020-10-19' , '2'),
('1' , '2020-10-21' , '1'),
('1' , '2020-11-02' , '3'),
('1' , '2020-11-11', '1');
CREATE TABLE tableB (
`id` int,
`name` varchar(19)
);
INSERT INTO tableB
(`id`, `name`)
VALUES
('1', 'lorem'),
('2', 'ipsum'),
('3', 'dolor');
SELECT b.`name`, Count(`tableB_id`)
FROM tableB b LEFT JOIN (SELECT * FROM tableA WHERE MONTH(`date`) = '10') a ON a.tableB_id = b.id
GROUP BY b.name
;
name | Count(`tableB_id`)
:---- | -----------------:
lorem | 1
ipsum | 2
dolor | 0
db<>fiddle here
You can use next php code:
$query = "SELECT
name Name, COUNT(tableA.id) Qty
FROM tableB
LEFT JOIN tableA ON tableB.id = tableA.tableB_id AND MONTH(tableA.date) = 10
GROUP BY tableB.name;";
// get DB version using PDO
$stmt = $pdo->prepare($query);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
print_r($rows);
Live PHP fiddle
Result:
Array
(
[0] => Array
(
[Name] => dolor
[Qty] => 0
)
[1] => Array
(
[Name] => ipsum
[Qty] => 2
)
[2] => Array
(
[Name] => lorem
[Qty] => 1
)
)

PDO Error Code 1060 Duplicate column name for Inserting Record to table

I tried to Insert Record to table using PDO but its always return this error Error : Array ( [0] => 42S21 [1] => 1060 [2] => Duplicate column name '' )
and Sometimes inserting perfectly. I don't understand why its happened.
$data=array(
':business_title' =>$title ,
':business_cover' => $cover,
':business_logo' => $logo,
':business_location'=>$location,
':business_address' =>$address,
':business_contact' =>$phone ,
':business_email' =>$email ,
':business_url' =>$website ,
':business_category' =>$category ,
':business_subcategory' =>$subcategory ,
':business_keywords' =>$keywords ,
':business_full_desc' => $summary,
':business_amenities' => $amenities,
':business_socialurl' => $socialurl,
':business_token' => $token,
':user_id' => $userid
);
$query = "
INSERT INTO tablename
(business_title,business_cover,business_logo,business_location,business_address,business_contact,business_email,business_url,business_category,business_subcategory,business_keywords,business_full_desc,business_amenities, business_socialurl,business_token, user_id)
SELECT * FROM (SELECT :business_title,:business_cover,:business_logo,:business_location,:business_address,:business_contact,:business_email,:business_url,:business_category,:business_subcategory,:business_keywords,:business_full_desc,:business_amenities, :business_socialurl,:business_token, :user_id) AS tmp
WHERE NOT EXISTS (
SELECT user_id FROM tablename WHERE user_id = :user_id
) LIMIT 1
";
Your problem is occurring when you get duplicated values in the input data. When you SELECT a set of constant values, MySQL automatically generates column names which match the values. For example:
SELECT 'a', 'b', 'c'
yields the result:
a b c
---------
a b c
Now if you
SELECT 'a', 'b', 'b'
You get
a b b
---------
a b b
As a result, if you then attempt to
SELECT * FROM (SELECT 'a', 'b', 'b') AS tmp;
You will get a duplicate column error as there are two columns called b in the result set of the subquery.
You can work around this by giving the values column aliases, for example:
SELECT * FROM (SELECT 'a' AS a, 'b' AS b, 'b' AS c) AS tmp;
Output:
a b c
a b b
Demo on dbfiddle
Note that it's not clear that you need the complexity of the query that you have, you should be able to simply:
INSERT INTO tablename (business_title,business_cover,business_logo,business_location,business_address,business_contact,business_email,business_url,business_category,business_subcategory,business_keywords,business_full_desc,business_amenities, business_socialurl,business_token, user_id)
SELECT :business_title,:business_cover,:business_logo,:business_location,:business_address,:business_contact,:business_email,:business_url,:business_category,:business_subcategory,:business_keywords,:business_full_desc,:business_amenities, :business_socialurl,:business_token, :user_id
WHERE NOT EXISTS (
SELECT * FROM tablename WHERE user_id = :user_id
)
See for example this demo.

issue with joins and not exist values

Here is my table looks..
Users
Id name height weight
1 aaa 1 10
2 bbb 4 104
3 ccc 1 10
4 ddd 56 150
5 eee 232 180
second table looks like
Profile view
Id sender receiver block
1 1 2 True
2 2 3 False
3 4 1 False
The problem i am facing is,,When I search using height and weight in users table and block using profileview table.I couldn't get proper results..
If second user bbb search with height "1" and weight "10" it should be appear 3rd user details ccc .First user also matched but First user blocked second user.The problem is when i using join values coming if sender and receiver exists i the profileview table.If not exist how do we do in joins..
CREATE TABLE #Users
(
Id int,
[Name] varchar(255),
Height int,
[Weight] int
)
CREATE TABLE #ProfileView
(
Id int,
Sender int,
Receiver int,
[Block] varchar(5)
)
INSERT INTO #Users
(Id, [Name], Height, [Weight])
VALUES
(1, 'aaa', 1, 10),
(2, 'bbb', 4, 104),
(3, 'ccc', 1, 10),
(4, 'ddd', 56, 150),
(5, 'eee', 232, 180)
INSERT INTO #ProfileView
(Id, Sender, Receiver, [Block])
VALUES
(1, 1, 2, 'True'),
(2, 2, 3, 'False'),
(3, 4, 1, 'False')
DECLARE
#CallingUser int, --User performing the search
#Height int, --Height searched for
#Weight int --Weight searched for
SET #CallingUser = 2
SET #Height = 1
SET #Weight = 10
SELECT
*
FROM
#Users
LEFT OUTER JOIN #ProfileView
ON #Users.Id = #ProfileView.Id
AND #ProfileView.Receiver = #CallingUser
WHERE
#Users.Id <> #CallingUser
AND #Users.Height = #Height
AND #Users.[Weight] = #Weight
AND (#ProfileView.[Block] = 'False' OR #ProfileView.[Block] IS NULL)
DROP TABLE #Users
DROP TABLE #ProfileView

Mysql query, two tables. Select only if value exists in other table

I have two tables, options and products. I want to select all from options but only if options.id exists in any of the products columns. This are my two tables:
options table:
id option value
1 'kategorija' 'Muški'
2 'kategorija' 'Ženski'
3 'kategorija' 'Dječji'
4 'brand' 'Casio'
5 'brand' 'Lorus'
6 'brand' 'Seiko'
7 'brand' 'Citizen'
8 'mehanizam' 'Quartz'
9 'mehanizam' 'Automatik'
10 'mehanizam' 'Eco-Drive'
11 'brojcanik' 'Analogni'
12 'brojcanik' 'Digitalni'
13 'grupa' 'Satovi'
14 'grupa' 'Naocale'
and the second table products:
id grupa brand mehanizam brojcanik kategorija
10380 '13' '4' '8' '11' '2'
10560 '13' '4' '9' '12' '1'
11100 '13' '6' '8' '11' '2'
12380 '14' '7' '8' '11' '2'
12490 '13' '6' '9' '11' '1'
15720 '14' '6' '9' '12' '1'
16550 '14' '5' '8' '12' '3'
my attempt for query:
SELECT * FROM options WHERE EXISTS( SELECT 1 FROM products WHERE grupa="14" AND brand=options.id OR mehanizam=options.id OR brojcanik=options.id OR kategorija=options.id)
the result should be:
Array
(
[0] => Array
(
[id] => 14
[option] => grupa
[value] => Naocale
)
[1] => Array
(
[id] => 7
[option] => brand
[value] => Citizen
)
[2] => Array
(
[id] => 8
[option] => mehanizam
[value] => Quartz
)
[3] => Array
(
[id] => 11
[option] => brojcanik
[value] => Analogni
)
[4] => Array
(
[id] => 2
[option] => kategorija
[value] => Zenski
)
)
This is array only for one row for products id 12380 which is grupa 14. Array should go on for the rest of products where there is grupa 14 found in products row.
I don't know if this is possible only with mysql query. If it's not possible i will have to do comparison with php which is what I'm trying to avoid.
Thanks
Based on your statement,
I want to select all from options but only if options.id exists in any
of the products columns.
You can combine all values using UNION ALL in a subquery and join the result with table options.
SELECT DISTINCT a.*
FROM options a
INNER JOIN
(
SELECT brand col FROM products WHERE grupa = 14
UNION ALL
SELECT mehanizam col FROM products WHERE grupa = 14
UNION ALL
SELECT brojcanik col FROM products WHERE grupa = 14
UNION ALL
SELECT kategorija col FROM products WHERE grupa = 14
) b ON a.id = b.col
Much better way,
SELECT *
FROM options a
WHERE EXISTS
(
SELECT 1
FROM products b
WHERE b.grupa = '14' AND
a.ID IN (brand, mehanizam, brojcanik, kategorija)
)
Instead of using specifically 14 you can simply join on options again
WHERE EXISTS (SELECT 1 FROM products JOIN options ON id = grupa ...

Categories