I have written the code shown below and I got the expected output. but,need the same output without use the same tables in inline view (such as tables join for UserPhoneDetail_JSON). thanks in advance
Code:
BEGIN
DROP TABLE #USERMASTER;
DROP TABLE #USERPHONE;
CREATE TABLE #USERMASTER (ID INT, NAME VARCHAR(100));
CREATE TABLE #USERPHONE (ID INT, PHONENUMBER NUMERIC,PHONETYPE CHAR(1));
INSERT INTO #USERMASTER VALUES(1,'JOHN');
INSERT INTO #USERMASTER VALUES(2,'VICTOR');
INSERT INTO #USERPHONE VALUES(1,1356487965,'W');
INSERT INTO #USERPHONE VALUES(1,9841007493,'M');
INSERT INTO #USERPHONE VALUES(1,7255952105,'O');
INSERT INTO #USERPHONE VALUES(2,9874563212,'M');
WITH E AS (SELECT A.ID,A.NAME,B.PHONENUMBER,B.PHONETYPE,ROW_NUMBER() OVER(PARTITION BY A.ID ORDER BY A.ID) RN
FROM #USERMASTER A JOIN #USERPHONE B ON A.ID=B.ID)
SELECT E.ID,
E.NAME,
E.PHONENUMBER,
E.PHONETYPE,
UserPhoneDetail_JSON = (
SELECT A.ID,B.PHONETYPE,PHONENUMBER,A.NAME FROM #USERMASTER A JOIN #USERPHONE B ON A.ID=B.ID
FOR JSON PATH )
FROM E WHERE RN=1;
END
output:
1 JOHN 1356487965 W [{"ID":1,"PHONETYPE":"W","PHONENUMBER":1356487965,"NAME":"JOHN"},{"ID":1,"PHONETYPE":"M","PHONENUMBER":9841007493,"NAME":"JOHN"},{"ID":1,"PHONETYPE":"O","PHONENUMBER":7255952105,"NAME":"JOHN"},{"ID":2,"PHONETYPE":"M","PHONENUMBER":9874563212,"NAME":"VICTOR"}]
2 VICTOR 9874563212 M [{"ID":1,"PHONETYPE":"W","PHONENUMBER":1356487965,"NAME":"JOHN"},{"ID":1,"PHONETYPE":"M","PHONENUMBER":9841007493,"NAME":"JOHN"},{"ID":1,"PHONETYPE":"O","PHONENUMBER":7255952105,"NAME":"JOHN"},{"ID":2,"PHONETYPE":"M","PHONENUMBER":9874563212,"NAME":"VICTOR"}]
EXPECTED OUTPUT:
1 JOHN 1356487965 W [{"ID":1,"PHONETYPE":"W","PHONENUMBER":1356487965,"NAME":"JOHN"},{"ID":1,"PHONETYPE":"M","PHONENUMBER":9841007493,"NAME":"JOHN"},{"ID":1,"PHONETYPE":"O","PHONENUMBER":7255952105,"NAME":"JOHN"}]
2 VICTOR 9874563212 M [{"ID":2,"PHONETYPE":"M","PHONENUMBER":9874563212,"NAME":"VICTOR"}]
If I understand you correctly and you need to generate JSON content for each first row per ID, this statement is an option:
SELECT
t.ID, t.NAME, t.PHONENUMBER, t.PHONETYPE,
UserPhoneDetail_JSON = (
SELECT t.ID, PHONETYPE, PHONENUMBER, t.NAME
FROM #USERPHONE
WHERE ID = t.ID
FOR JSON PATH
)
FROM (
SELECT
m.ID, m.NAME, p.PHONENUMBER, p.PHONETYPE,
ROW_NUMBER() OVER (PARTITION BY m.ID ORDER BY p.ID) RN
FROM #USERMASTER m
JOIN #USERPHONE p ON m.ID = p.ID
) t
WHERE t.RN = 1
Related
For example have such structure:
CREATE TABLE clicks
(`date` varchar(50), `sum` int, `id` int)
;
CREATE TABLE marks
(`click_id` int, `name` varchar(50), `value` varchar(50))
;
where click can have many marks
So example data:
INSERT INTO clicks
(`sum`, `id`, `date`)
VALUES
(100, 1, '2017-01-01'),
(200, 2, '2017-01-01')
;
INSERT INTO marks
(`click_id`, `name`, `value`)
VALUES
(1, 'utm_source', 'test_source1'),
(1, 'utm_medium', 'test_medium1'),
(1, 'utm_term', 'test_term1'),
(2, 'utm_source', 'test_source1'),
(2, 'utm_medium', 'test_medium1')
;
I need to get agregated values of click grouped by date which contains all of selected values.
I make request:
select
c.date,
sum(c.sum)
from clicks as c
left join marks as m ON m.click_id = c.id
where
(m.name = 'utm_source' AND m.value='test_source1') OR
(m.name = 'utm_medium' AND m.value='test_medium1') OR
(m.name = 'utm_term' AND m.value='test_term1')
group by date
and get 2017-01-01 = 700, but I want to get 100 which means that only click 1 has all of marks.
Or if condition will be
(m.name = 'utm_source' AND m.value='test_source1') OR
(m.name = 'utm_medium' AND m.value='test_medium1')
I need to get 300 instead of 600
I found answer in getting distinct click_id by first query and then sum and group by date with condition whereIn, but on real database which is very large and has id as uuid this request executes extrimely slow. Any advices how to get it work propely?
You can achieve it using below queries:
When there are the three conditions then you have to pass the HAVING count(*) >= 3
SELECT cc.DATE
,sum(cc.sum)
FROM clicks AS cc
INNER JOIN (
SELECT id
FROM clicks AS c
LEFT JOIN marks AS m ON m.click_id = c.id
WHERE (
m.NAME = 'utm_source'
AND m.value = 'test_source1'
)
OR (
m.NAME = 'utm_medium'
AND m.value = 'test_medium1'
)
OR (
m.NAME = 'utm_term'
AND m.value = 'test_term1'
)
GROUP BY id
HAVING count(*) >= 3
) AS t ON cc.id = t.id
GROUP BY cc.DATE
When there are the three conditions then you have to pass the HAVING count(*) >= 2
SELECT cc.DATE
,sum(cc.sum)
FROM clicks AS cc
INNER JOIN (
SELECT id
FROM clicks AS c
LEFT JOIN marks AS m ON m.click_id = c.id
WHERE (
m.NAME = 'utm_source'
AND m.value = 'test_source1'
)
OR (
m.NAME = 'utm_medium'
AND m.value = 'test_medium1'
)
GROUP BY id
HAVING count(*) >= 2
) AS t ON cc.id = t.id
GROUP BY cc.DATE
Demo: http://sqlfiddle.com/#!9/fe571a/35
Hope this works for you...
You're getting 700 because the join generates multiple rows for the different IDs. There are 3 rows in the mark table with ID=1 and sum=100 and there are two rows with ID=2 and sum=200. On doing the join where shall have 3 rows with sum=100 and 2 rows with sum=200, so adding these sum gives 700. To fix this you have to aggregate on the click_id too as illustrated below:
select
c.date,
sum(c.sum)
from clicks as c
inner join (select * from marks where (name = 'utm_source' AND
value='test_source1') OR (name = 'utm_medium' AND value='test_medium1')
OR (name = 'utm_term' AND value='test_term1')
group by click_id) as m
ON m.click_id = c.id
group by c.date;
DEMO SQL FIDDLE
I found the right way myself, which works on large amounts of data
The main goal is to make request generate one table with subqueries(conditions) which do not depend on amount of data in results, so the best way is:
select
c.date,
sum(c.sum)
from clicks as c
join marks as m1 ON m1.click_id = c.id
join marks as m2 ON m2.click_id = c.id
join marks as m3 ON m3.click_id = c.id
where
(m1.name = 'utm_source' AND m1.value='test_source1') AND
(m2.name = 'utm_medium' AND m2.value='test_medium1') AND
(m3.name = 'utm_term' AND m3.value='test_term1')
group by date
So we need to make as many joins as many conditions we have
Here I have a simple table. I would like to end up with a table like the one given. What is the best way to write the sql statement to achieve this?
Table 1
Id Name Approved
1 Australia 3
2 UAE 1
3 India 2
Table 2
Id Status
1 Submit
2 In-Progress
3 Pending
Show result as
Submitted In-Progress Pending
UAE India Australia
Please Try below query:
create table #country
(
ID int identity(1,1),
Name varchar(30),
Approved int
)
create table #status
(
ID int,
Status varchar(30)
)
insert into #country (Name, Approved) values ('Australia',3), ('UAE',1), ('India',2)
insert into #status (ID, Status) values (1,'Submit'), (2, 'In-Progress'), (3,'Pending')
select Submit, [In-Progress],[Pending]
from (
select t1.Name, t2.Status
from #country t1
inner join #status t2 on t1.Approved = t2.ID
)dd1
pivot (
max(Name) for Status in ([Submit], [In-Progress],[Pending])
) piv
drop table #country
drop table #status
Output of this query:
Try this:-
select
trim(replace(group_concat(submitted),',',' ')) as submitted,
trim(replace(group_concat(InProgress),',',' ')) as InProgress,
trim(replace(group_concat(Pending),',',' ')) as Pending
from
(
Select
case when status='Submit' then A.Name else ' ' end as submitted,
case when status='In-Progress' then A.Name else ' ' end as InProgress,
case when status='Pending' then A.Name else ' ' end as Pending
FROM
TABLE1 A
INNER JOIN
TABLE2 B
ON A.ID=B.ID
) a;
Here's the answer as of given Data:
select `Submit`,`In-Progress`,`Pending` from
(select `Submit`,`In-Progress`,INP.id from
(select Name as 'Submit',a.id from
(select * from table1)as a
LEFT JOIN
(select * from table2) as b
on a.Approvide = b.`Id`
where b.`STATUS` = 'Submit') as Sub
INNER JOIN
(select Name as 'In-Progress',a.id from
(select * from table1)as a
LEFT JOIN
(select * from table2) as b
on a.Approvide = b.`Id`
where b.`STATUS` = 'In-Progress') as INP
on Sub.id != INP.id) as c
INNER JOIN
(select Name as Pending,a.id from
(select * from table1)as a
LEFT JOIN
(select * from table2) as b
on a.Approvide = b.`Id`
where b.`STATUS` = 'Pending') as Pen
on c.id != Pen.id
select Name,Status from Table1 natural join Table2;
That's simple. The result should look like this now. I think this is usual approach that how we actually retrieve the information from multiple tables.
Name Status
Australia Pending
UAE Submit
India In-Progress
Please consider
I have this table: http://sqlfiddle.com/#!2/b4060/2
I then created two views as follow:
-- stack 1: hire
create view HS1H as
select a.* , min(a.`Effective_Date`)
from `Table1` a
left join `Table1` b on a.`Employee_ID` = b.`Employee_ID`
and a.`Effective_Date` > b.`Effective_Date`
where a.`Event_Type` = "1_Hire"
group by a.`Employee_ID`;
select * from `hs1h`;
-- stack 1: termination
create view HS1T as
select a.* , min(a.`Effective_Date`)
from `Table1` a
left join `Table1` b on a.`Employee_ID` = b.`Employee_ID`
and a.`Effective_Date` > b.`Effective_Date`
where a.`Event_Type` = "5_Term"
group by a.`Employee_ID`;
select * from `hs1t`;
I want to get the events that happen between first Hire date and first Term date. I used the qry below but returned no results:
select a.*
from `Table1` a
join `hs1h` b on a.`Employee_ID` = b.`Employee_ID`
join `hs1t` c on a.`Employee_ID` = c.`Employee_ID`
where a.`Effective_Date` between b.`Effective_Date` and c.`Effective_Date`;
I am not sure what went wrong. I was able run the following two qrys. One returned the events after first hire date, and the other returned the events before first term date. But when I combine them like the one above, it didn't work.
select a.*
from `Table1` a
join `hs1h` b on a.`Employee_ID` = b.`Employee_ID`
join `hs1t` c on a.`Employee_ID` = c.`Employee_ID`
where a.`Effective_Date` > b.`Effective_Date`;
select a.*
from `Table1` a
join `hs1h` b on a.`Employee_ID` = b.`Employee_ID`
join `hs1t` c on a.`Employee_ID` = c.`Employee_ID`
where a.`Effective_Date` < c.`Effective_Date`;
SELECT *
FROM table1
WHERE `effective date`
BETWEEN (select MIN(`effective date`) from `Table1` WHERE `event type` = '1_Hire')
AND
(select MIN(`effective date`) FROM table1 WHERE `event type` = '5_Term')
For the 2nd or 3rd 'hire', things get a little more complicated, but something like this should work...
SELECT a.*
FROM TH_Sample_Data a
JOIN (
SELECT x.*
, MIN(y.effective_date) end
, #i := #i+1 rank
FROM TH_Sample_Data x
JOIN TH_Sample_Data y
ON y.effective_date >= x.effective_date
AND y.event_type = '5_Term'
, (SELECT #i:=1) vars
WHERE x.event_type = '1_Hire'
GROUP
BY x.id
) b
ON a.effective_date BETWEEN b.effective_date and b.end
WHERE b.rank = 2;
I'm trying to create a query to update the rank field of all the records in the table, based on values from the same table.
I managed to get a working SELECT query that calculates the rank, but I'm having a hard time converting it to an UPDATE. This is the query:
SELECT
((views_count + comments_count) * (172800 / elapsed)) AS rank
FROM (
SELECT
p.views_count,
(UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(p.createdAt)) AS elapsed,
(SELECT COUNT(*) FROM `comments` AS c WHERE c.photo_id = p.id) AS comments_count
FROM `photos` AS p
) AS m
How can I implant it in an UPDATE query, to update each record's rank value?
Thanks! :)
EDIT:
My DB structure:
[Photo]
id
user_id
views_count
rank
createdAt
[Comment]
id
photo_id
content
Just a guess, but something like this should work:
UPDATE `photos`
FROM (
SELECT id
, (views_count + comments_count) * (172800 / elapsed) AS rank
FROM (
SELECT p.id
, p.views_count
, ( UNIX_TIMESTAMP(NOW())
- UNIX_TIMESTAMP(p.createdAt)) AS elapsed
, (SELECT COUNT(*)
FROM `comments` AS c
WHERE c.photo_id = p.id) AS comments_count
FROM `photos` AS p
) AS m
) AS z
SET rank=z.rank
WHERE `photos`.id=z.id
You should write your new ranks to a temporary table and use that to update the original table. try
CREATE TEMPORARY TABLE tmp_tbl AS (
SELECT ((views_count + comments_count) * (172800 / elapsed)) AS rank, m.id
FROM (SELECT
p.views_count,
(UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(p.createdAt)) AS elapsed,
(SELECT COUNT(*) FROM `comments` AS c WHERE c.photo_id = p.id) AS comments_count
FROM `photos` AS p
) AS m);
and then
UPDATE photos, tmp_tbl SET photos.rank = tmp_tbl.rank WHERE photos.id=tmp_tbl.id;
and finally
DROP TABLE tmp_tbl;
See this simliar stackoverflow question
Good day
I am trying to query the names of employees who work on every project.
My code is as follows:
SELECT CONCAT (fname,' ', minit,'. ' , lname) AS NAME
FROM employee a, works_on b, project c
WHERE pno IN (Select pnumber //WHAT COULD I SUBSTITUTE W/ IN
FROM projet)
AND a.ssn = b.essn
AND b.pno = c.pnumber
The problem with IN is that it is that the values inside are like evaluated as 'OR'... what is the equivalent of IN that makes the value of my subquery evaluated like 'AND'
Thank you in advance.
EDIT:
As reqeusted..
SELECT *
FROM employee e
WHERE NOT EXISTS
(
SELECT NULL
FROM employee ei
CROSS JOIN
project p
LEFT JOIN
works_on wo
ON wo.pno = p.pnumber
AND wo.essn = ei.ssn
WHERE ei.ssn = e.ssn
)
select CONCAT (fname,' ', minit,'. ' , lname) AS NAME
from employee
left join works_on
on works_on.essn=employee.ssn
group by employee.ssn
having count(works_on.essn) = (select count(*) from project);
Simplified example:
create table emp_work_on
(
emp_name varchar(50),
work_on varchar(30)
);
create table works
(
work_on varchar(30)
);
insert into works(work_on) values('apple'),('microsoft'),('google'),('facebook')
insert into emp_work_on values
('john','apple'),('john','microsoft'),('john','google'),('john','facebook'),
('paul','microsoft'),('paul','google'),
('george','apple'),('george','microsoft'),('george','google'),('george','facebook'),
('ringo','apple'),('ringo','facebook');
select e.emp_name
from works w
left join emp_work_on e on e.work_on = w.work_on
group by e.emp_name
having count(e.work_on) = (select count(*) from works)
order by e.emp_name
Output:
emp_name
----------
george
john
(2 rows)
On your table structure, you could use this:
SELECT * FROM employee
WHERE ssn IN
(
SELECT w.essn
FROM project c
LEFT JOIN works_on w ON w.pno = c.pnumber
GROUP BY w.essn
HAVING COUNT(w.pno) = (SELECT COUNT(*) FROM project)
)
Hmm.. but I think this could be the simplest, granting there's no repeating pno on employee's works_on, i.e. there's no pno in works_on that doesn't exists on project, i.e. referential integrity is maintained
SELECT * FROM employee
WHERE ssn IN
(
SELECT essn
FROM works_on
GROUP BY essn
HAVING COUNT(pno) = (SELECT COUNT(*) FROM project)
)