SQL Statement(s) - sql

If I have the following table:
CREATE TABLE #temp (
id int,
num int,
question varchar(50),
qversion int );
INSERT INTO #temp VALUES(1, 1, 'Question 1 v1', 1);
INSERT INTO #temp VALUES(2, 1, 'Question 1 v2', 2);
INSERT INTO #temp VALUES(3, 2, 'Question 2 v1', 1);
INSERT INTO #temp VALUES(4, 2, 'Question 2 v2', 2);
INSERT INTO #temp VALUES(5, 2, 'Question 2 v3', 3);
INSERT INTO #temp VALUES(6, 3, 'Question 3 v1', 1);
SELECT *
FROM #temp;
DROP TABLE #temp;
And I would like to get a table to display the three questions in their lastest version? This is in SQL Server 2005

CREATE TABLE #temp (
id int,
num int,
question varchar(50),
qversion int );
INSERT INTO #temp VALUES(1, 1, 'Question 1 v1', 1);
INSERT INTO #temp VALUES(2, 1, 'Question 1 v2', 2);
INSERT INTO #temp VALUES(3, 2, 'Question 2 v1', 1);
INSERT INTO #temp VALUES(4, 2, 'Question 2 v2', 2);
INSERT INTO #temp VALUES(5, 2, 'Question 2 v3', 3);
INSERT INTO #temp VALUES(6, 3, 'Question 3 v1', 1);
WITH latest AS (
SELECT num, MAX(qversion) AS qversion
FROM #temp
GROUP BY num
)
SELECT #temp.*
FROM #temp
INNER JOIN latest
ON latest.num = #temp.num
AND latest.qversion = #temp.qversion;
DROP TABLE #temp;

SELECT t1.id, t1.num, t1.question, t1.qversion
FROM #temp t1
LEFT OUTER JOIN #temp t2
ON (t1.num = t2.num AND t1.qversion < t2.qversion)
GROUP BY t1.id, t1.num, t1.question, t1.qversion
HAVING COUNT(*) < 3;

You're using SQL Server 2005, so it's worth at least exploring the over clause:
select
*
from
(select *, max(qversion) over (partition by num) as maxVersion from #temp) s
where
s.qversion = s.maxVersion

I would like to get a table to display the three latest versions of each question.
I assume that that qversion is increasing with time. If this assumption is backwards, remove the desc keyword from the answer.
The table definition does not have an explicit not null constraint on qversion. I assume that a null qversion should be excluded. (Note: Depending on settings, lack of an explicit null/not null in the declaration may result in a not null constraint.) If the table does have a not null contraint, than the text where qversion is not null should be removed. If qversion can be null, and nulls need to be included in the result set, then additional changes will need to be made.
CREATE TABLE #temp (
id int,
num int,
question varchar(50),
qversion int );
INSERT INTO #temp VALUES(1, 1, 'Question 1 v1', 1);
INSERT INTO #temp VALUES(2, 1, 'Question 1 v2', 2);
INSERT INTO #temp VALUES(3, 2, 'Question 2 v1', 1);
INSERT INTO #temp VALUES(4, 2, 'Question 2 v2', 2);
INSERT INTO #temp VALUES(5, 2, 'Question 2 v3', 3);
INSERT INTO #temp VALUES(7, 2, 'Question 2 v4', 4);
-- ^^ Added so at least one row would be excluded.
INSERT INTO #temp VALUES(6, 3, 'Question 3 v1', 1);
INSERT INTO #temp VALUES(8, 4, 'Question 4 v?', null);
select id, num, question, qversion
from (select *,
row_number() over (partition by num order by qversion desc) as RN
from #temp
where qversion is not null) T
where RN <= 3

Related

access convert to sql

how can i convert this access statement to sql ?
DELETE [Find duplicates for tBDEDom].* FROM [Find duplicates for tBDEDom];
CREATE TABLE #tBDEDom( Id int, Name VARCHAR(10))
insert into #tBDEDom values(1, 'abc')
insert into #tBDEDom values(2, 'mpo')
insert into #tBDEDom values(3, 'atc')
insert into #tBDEDom values(4, 'xyz')
insert into #tBDEDom values(5, 'abc')
insert into #tBDEDom values(6, 'xyz')
insert into #tBDEDom values(7, 'abc')
SELECT * FROM #tBDEDom
;with cte
AS(
SELECT *, ROW_NUMBER()OVER(partition by Name order by Name) AS [rank] FROM #tBDEDom
)
DELETE FROM cte where [rank]>1
SELECT * FROM #tBDEDom
DROP TABLE #tBDEDom

sql join joining 3 tables

bit of a strange one this one...
Someone wrote a sql that in my mind shouldn't work, but it does and it also returns the correct results. I've written a simplified example, but I think it shows the point.
drop table #client;
drop table #transactions;
drop table #history;
create table #client (
clientId int,
name varchar(50)
);
create table #transactions (
transid int,
clientId int,
Amount int
);
create table #history (
transid int,
Amount int
);
insert into #client values (1, 'User 1');
insert into #client values (2, 'User 2');
insert into #client values (3, 'User 3');
insert into #transactions values (1, 1, 50);
insert into #transactions values (2, 1, 35);
insert into #transactions values (3, 1, 25);
insert into #transactions values (4, 2, 10);
insert into #transactions values (5, 2, 50);
insert into #transactions values (6, 1, 35);
insert into #transactions values (7, 3, 25);
insert into #transactions values (8, 3, 10);
insert into #history values (1, 50);
insert into #history values (2, 35);
insert into #history values (3, 25);
insert into #history values (4, 10);
insert into #history values (5, 50);
insert into #history values (6, 35);
insert into #history values (7, 25);
insert into #history values (8, 10);
select * from #history
join #transactions on #history.transid = #transactions.transid
join #client on #transactions.clientId = #client.clientId and #history.transid = #transactions.transid
The last join joins 3 tables together in one join, which shouldn't work from what I know of writing SQL. Am I wrong (which may very well be the case)
Why would you think it shouldn't work?
The last bit of the query is pointless though, and you can take it out. It's a simple join on 3 tables:
select * from #history
join #transactions on #history.transid = #transactions.transid
join #client on #transactions.clientId = #client.clientId

SQL merging tables [duplicate]

This question already has answers here:
Efficiently convert rows to columns in sql server
(5 answers)
Closed 8 years ago.
I am trying to merge a few tables in order to get the output as outlined in the image below.
My issue is that I am not sure what type of joins to use to achieve that
Can someone please help me with the syntax.
You could do something like this, it's a dynamic pivot as you might add/ take away users?
CREATE TABLE #Tests (
Test_ID INT,
TestName VARCHAR(50));
INSERT INTO #Tests VALUES (1, 'SQL Test');
INSERT INTO #Tests VALUES (2, 'C# Test');
INSERT INTO #Tests VALUES (3, 'Java Test');
CREATE TABLE #Users (
[User_ID] INT,
UserName VARCHAR(50));
INSERT INTO #Users VALUES (1, 'Joe');
INSERT INTO #Users VALUES (2, 'Jack');
INSERT INTO #Users VALUES (3, 'Jane');
CREATE TABLE #UserTests (
ID INT,
[User_ID] INT,
Test_ID INT,
Completed INT);
INSERT INTO #UserTests VALUES (1, 1, 1, 0);
INSERT INTO #UserTests VALUES (2, 1, 2, 1);
INSERT INTO #UserTests VALUES (3, 1, 3, 1);
INSERT INTO #UserTests VALUES (4, 2, 1, 0);
INSERT INTO #UserTests VALUES (5, 2, 2, 0);
INSERT INTO #UserTests VALUES (6, 2, 3, 0);
INSERT INTO #UserTests VALUES (7, 3, 1, 1);
INSERT INTO #UserTests VALUES (8, 3, 2, 1);
INSERT INTO #UserTests VALUES (9, 3, 3, 1);
DECLARE #Cols VARCHAR(MAX);
SELECT #Cols = STUFF((SELECT distinct ',' + QUOTENAME(u.UserName)
FROM #Users u
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
DECLARE #Query NVARCHAR(MAX);
SELECT #Query = 'SELECT TestName, ' + #Cols + ' FROM
(
SELECT
t.TestName,
u.UserName,
ut.Completed
FROM
#Tests t
INNER JOIN #UserTests ut ON ut.Test_ID = t.Test_ID
INNER JOIN #Users u ON u.[User_ID] = ut.[User_ID]) x
PIVOT (
MAX(Completed)
FOR UserName IN (' + #Cols + ')
) AS pt';
EXEC(#Query);
Results are:
TestName Jack Jane Joe
C# Test 0 1 1
Java Test 0 1 1
SQL Test 0 1 0
(Same results as yours, but in a different sort order.)

How do I remove all but some records based on a threshold?

I have a table like this:
CREATE TABLE #TEMP(id int, name varchar(100))
INSERT INTO #TEMP VALUES(1, 'John')
INSERT INTO #TEMP VALUES(1, 'Adam')
INSERT INTO #TEMP VALUES(1, 'Robert')
INSERT INTO #TEMP VALUES(1, 'Copper')
INSERT INTO #TEMP VALUES(1, 'Jumbo')
INSERT INTO #TEMP VALUES(2, 'Jill')
INSERT INTO #TEMP VALUES(2, 'Rocky')
INSERT INTO #TEMP VALUES(2, 'Jack')
INSERT INTO #TEMP VALUES(2, 'Lisa')
INSERT INTO #TEMP VALUES(3, 'Amy')
SELECT *
FROM #TEMP
DROP TABLE #TEMP
I am trying to remove all but some records for those that have more than 3 names with the same id. Therefore, I am trying to get something like this:
id name
1 Adam
1 Copper
1 John
2 Jill
2 Jack
2 Lisa
3 Amy
I am not understanding how to write this query. I have gotten to the extent of preserving one record but not a threshold of records:
;WITH FILTER AS
(
SELECT id
FROM #TEMP
GROUP BY id
HAVING COUNT(id) >=3
)
SELECT id, MAX(name)
FROM #TEMP
WHERE id IN (SELECT * FROM FILTER)
GROUP BY id
UNION
SELECT id, name
FROM #TEMP
WHERE id NOT IN (SELECT * FROM FILTER)
Gives me:
1 Robert
2 Rocky
3 Amy
Any suggestions? Oh by the way, I don't care what records are preserved while merging.
You can do it using CTE
CREATE TABLE #TEMP(id int, name varchar(100))
INSERT INTO #TEMP VALUES(1, 'John')
INSERT INTO #TEMP VALUES(1, 'Adam')
INSERT INTO #TEMP VALUES(1, 'Robert')
INSERT INTO #TEMP VALUES(1, 'Copper')
INSERT INTO #TEMP VALUES(1, 'Jumbo')
INSERT INTO #TEMP VALUES(2, 'Jill')
INSERT INTO #TEMP VALUES(2, 'Rocky')
INSERT INTO #TEMP VALUES(2, 'Jack')
INSERT INTO #TEMP VALUES(2, 'Lisa')
INSERT INTO #TEMP VALUES(3, 'Amy')
SELECT *
FROM #TEMP;
WITH CTE(N) AS
(
SELECT ROW_NUMBER() OVER(PARTITION BY id ORDER BY id)
FROM #Temp
)
DELETE CTE WHERE N>3;
SELECT *
FROM #TEMP;
DROP TABLE #TEMP
I will change your select like this (not tested)
select name from #temp group by name having count(id) > 3
then you can implement your query in a delete statement using your select as a where clause
in inner query you can use row_number function over (partition by id)
and then in outer query you have to give condition like below
select id,name from (
SELECT id,name, row_number() over (partition by id order by 1) count_id FROM #test
group by id, name )
where count_id <=3
If i got your question right, you need to get rows when id occurrence 3 or more times
select t1.name,t1.id from tbl1 t1
inner join tbl1 t2 on t1.id = t2.id
group by t1.name, t1.id
having count(t1.id) > 2

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