How do I limit a query with distinct values in MariaDB - sql

I have a table like this:
Id Num Some text
--------------------
1 1 ""
2 1 ""
3 2 ""
4 2 ""
5 2 ""
6 2 ""
7 3 ""
What I want is a query to select the first ten distinct nums, so if I want to get the two first nums I'll get the first six rows. I'm using MariaDB.

Try this approach:
select *
from Table1 as T1
join (
select distinct num
from Table1
order by num
limit 2 ) as T2
on T1.num = T2.num
;
In a fiddle here: http://sqlfiddle.com/#!9/1468ad/5

In MySQL you can use LIMIT. The caveat is that LIMIT is not directly supported in the IN sub-queries and therefore you must use a sub-query inside a IN sub-query:
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE Table1
(`Id` int, `Num` int, `Some text` varchar(2))
;
INSERT INTO Table1
(`Id`, `Num`, `Some text`)
VALUES
(1, 1, '""'),
(2, 1, '""'),
(3, 2, '""'),
(4, 2, '""'),
(5, 2, '""'),
(6, 2, '""'),
(7, 3, '""')
;
Query 1:
select * from Table1
where Num in (select Num FROM(select distinct Num from Table1 order by Num limit 2)a)
Results:
| Id | Num | Some text |
|----|-----|-----------|
| 1 | 1 | "" |
| 2 | 1 | "" |
| 3 | 2 | "" |
| 4 | 2 | "" |
| 5 | 2 | "" |
| 6 | 2 | "" |

Related

Roll up multiple rows into one when joining in SQL Server

I have a table, Foo
ID | Name
-----------
1 | ONE
2 | TWO
3 | THREE
And another, Bar:
ID | FooID | Value
------------------
1 | 1 | Alpha
2 | 1 | Alpha
3 | 1 | Alpha
4 | 2 | Beta
5 | 2 | Gamma
6 | 2 | Beta
7 | 3 | Delta
8 | 3 | Delta
9 | 3 | Delta
I would like a query that joins these tables, returning one row for each row in Foo, rolling up the 'value' column from Bar. I can get back the first Bar.Value for each FooID:
SELECT * FROM Foo f OUTER APPLY
(
SELECT TOP 1 Value FROM Bar WHERE FooId = f.ID
) AS b
Giving:
ID | Name | Value
---------------------
1 | ONE | Alpha
2 | TWO | Beta
3 | THREE | Delta
But that's not what I want, and I haven't been able to find a variant that will bring back a rolled up value, that is the single Bar.Value if it is the same for each corresponding Foo, or a static string something like '(multiple)' if not:
ID | Name | Value
---------------------
1 | ONE | Alpha
2 | TWO | (multiple)
3 | THREE | Delta
I have found some solutions that would bring back concatenated values (albeit not very elegant) 'Alpha' Alpha, Alpha', 'Beta, Gamma, Beta' &c, but that's not what I want either.
One method, using a a CASE expression and assuming that [Value] cannot have a value of NULL:
WITH Foo AS
(SELECT *
FROM (VALUES (1, 'ONE'),
(2, 'TWO'),
(3, 'THREE')) V (ID, [Name])),
Bar AS
(SELECT *
FROM (VALUES (1, 1, 'Alpha'),
(2, 1, 'Alpha'),
(3, 1, 'Alpha'),
(4, 2, 'Beta'),
(5, 2, 'Gamma'),
(6, 2, 'Beta'),
(7, 3, 'Delta'),
(8, 3, 'Delta'),
(9, 3, 'Delta')) V (ID, FooID, [Value]))
SELECT F.ID,
F.[Name],
CASE COUNT(DISTINCT B.[Value]) WHEN 1 THEN MAX(B.Value) ELSE '(Multiple)' END AS [Value]
FROM Foo F
JOIN Bar B ON F.ID = B.FooID
GROUP BY F.ID,
F.[Name];
You can also try below:
SELECT F.ID, F.Name, (case when B.Value like '%,%' then '(Multiple)' else B.Value end) as Value
FROM Foo F
outer apply
(
select SUBSTRING((
SELECT distinct ', '+ isnull(Value,',') FROM Bar WHERE FooId = F.ID
FOR XML PATH('')
), 2 , 9999) as Value
) as B

Creating natural hierarchical order using recursive SQL

I have a table holding categories with an inner parent child relationship.
The table looks like this:
ID | ParentID | OrderID
---+----------+---------
1 | Null | 1
2 | Null | 2
3 | 2 | 1
4 | 1 | 1
OrderID is the order inside the current level.
I want to create a recursive SQL query to create the natural order of the table.
Meaning the output will be something like:
ID | Order
-----+-------
1 | 100
4 | 101
2 | 200
3 | 201
Appreciate any help.
Thanks
I am not really sure what you mean by "natural order", but the following query generates the results you want for this data:
with t as (
select v.*
from (values (1, NULL, 1), (2, NULL, 2), (3, 2, 1), (4, 1, 1)) v(ID, ParentID, OrderID)
)
select t.*,
(100 * coalesce(tp.orderid, t.orderid) + (case when t.parentid is null then 0 else 1 end)) as natural_order
from t left join
t tp
on t.parentid = tp.id
order by natural_order;

Count Based on Columns in SQL Server

I have 3 tables:
SELECT id, letter
FROM As
+--------+--------+
| id | letter |
+--------+--------+
| 1 | A |
| 2 | B |
+--------+--------+
SELECT id, letter
FROM Xs
+--------+------------+
| id | letter |
+--------+------------+
| 1 | X |
| 2 | Y |
| 3 | Z |
+--------+------------+
SELECT id, As_id, Xs_id
FROM A_X
+--------+-------+-------+
| id | As_id | Xs_id |
+--------+-------+-------+
| 9 | 1 | 1 |
| 10 | 1 | 2 |
| 11 | 2 | 3 |
| 12 | 1 | 2 |
| 13 | 2 | 3 |
| 14 | 1 | 1 |
+--------+-------+-------+
I can count all As and Bs with group by. But I want to count As and Bs based on X,Y and Z. What I want to get is below:
+-------+
| X,Y,Z |
+-------+
| 2,2,0 |
| 0,0,2 |
+-------+
X,Y,Z
A 2,2,0
B 0,0,2
What is the best way to do this at MSSQL? Is it an efficent way to use foreach for example?
edit: It is not a duplicate because I just wanted to know the efficent way not any way.
For what you're trying to do without knowing what is inefficient with your current code (because none was provided), a Pivot is best. There are a million resources online and here in the stack overflow Q/A forums to find what you need. This is probably the simplest explanation of a Pivot which I frequently need to remind myself of the complicated syntax of a pivot.
To specifically answer your question, this is the code that shows how the link above applies to your question
First Tables needed to be created
DECLARE #AS AS TABLE (ID INT, LETTER VARCHAR(1))
DECLARE #XS AS TABLE (ID INT, LETTER VARCHAR(1))
DECLARE #XA AS TABLE (ID INT, AsID INT, XsID INT)
Values were added to the tables
INSERT INTO #AS (ID, Letter)
SELECT 1,'A'
UNION
SELECT 2,'B'
INSERT INTO #XS (ID, Letter)
SELECT 1,'X'
UNION
SELECT 2,'Y'
UNION
SELECT 3,'Z'
INSERT INTO #XA (ID, ASID, XSID)
SELECT 9,1,1
UNION
SELECT 10,1,2
UNION
SELECT 11,2,3
UNION
SELECT 12,1,2
UNION
SELECT 13,2,3
UNION
SELECT 14,1,1
Then the query which does the pivot is constructed:
SELECT LetterA, [X],[Y],[Z]
FROM (SELECT A.LETTER AS LetterA
,B.LETTER AS LetterX
,C.ID
FROM #XA C
JOIN #AS A
ON A.ID = C.ASID
JOIN #XS B
ON B.ID = C.XSID
) Src
PIVOT (COUNT(ID)
FOR LetterX IN ([X],[Y],[Z])
) AS PVT
When executed, your results are as follows:
Letter X Y Z
A 2 2 0
B 0 0 2
As i said in comment ... just join and do simple pivot
if object_id('tempdb..#AAs') is not null drop table #AAs
create table #AAs(id int, letter nvarchar(5))
if object_id('tempdb..#XXs') is not null drop table #XXs
create table #XXs(id int, letter nvarchar(5))
if object_id('tempdb..#A_X') is not null drop table #A_X
create table #A_X(id int, AAs int, XXs int)
insert into #AAs (id, letter) values (1, 'A'), (2, 'B')
insert into #XXs (id, letter) values (1, 'X'), (2, 'Y'), (3, 'Z')
insert into #A_X (id, AAs, XXs)
values (9, 1, 1),
(10, 1, 2),
(11, 2, 3),
(12, 1, 2),
(13, 2, 3),
(14, 1, 1)
select LetterA,
ISNULL([X], 0) [X],
ISNULL([Y], 0) [Y],
ISNULL([Z], 0) [Z]
from (
select distinct a.letter [LetterA], x.letter [LetterX],
count(*) over (partition by a.letter, x.letter order by a.letter) [Counted]
from #A_X ax
join #AAs A on ax.AAs = A.ID
join #XXs X on ax.XXs = X.ID
)src
PIVOT
(
MAX ([Counted]) for LetterX in ([X], [Y], [Z])
) piv
You get result as you asked for
LetterA X Y Z
A 2 2 0
B 0 0 2

Select items by column value

I have a table in SQL used to store result like so
Result
---------------
ID | DateCreated
1 | 2014-10-10
The Items under the result above
ResultItems
---------------
ResultID | StudentID | SubjID | Test1 | Test2 | Exam
1 | 1 | 1 | 7 | 7 | 30
1 | 2 | 1 | 8 | 8 | 35
1 | 1 | 2 | 5 | 5 | 45
1 | 2 | 2 | 6 | 6 | 40
I need to select from this tables so that each subject is in its own column, with the score of each subject summed under it
Result items
Result Output
---------------
StudentID| SubjID-1 | SubjID-2
1 | 44 | 55
2 | 51 | 52
I did try quiet some queries, such as this one below, which didn't give the result I needed
SELECT r.*,
ri.StudentID,
ri.Test1,
ri.Test2,
ri.Exam,
( ri.Test1+ ri.Test2 + ri.Exam ) Total
FROM Result r
LEFT JOIN ResultItems ri
ON ri.ResultID = r.id
WHERE ri.Test1 <> '-'
AND
ri.Test2 <> '-'
AND
ri.exam <> '-';
How can I amend this query?
Edit
I read about Pivot and saw this question SQL - columns for different categories, in which case the names/id of the subject has to be know before hand, which would not work for my case
Solution for SQL Server
All you need is called Pivot.
CREATE TABLE #ResultItems
(
ResultID INT,
StudentID INT,
SubjID INT,
Test1 INT,
Test2 INT,
Exam INT
)
INSERT INTO #ResultItems (ResultID, StudentID, SubjID, Test1, Test2, Exam)
VALUES(1, 1 , 1 , 7, 7, 30),
(1, 2 , 1 , 8, 8, 35),
(1, 1 , 2 , 5, 5, 45),
(1, 2 , 2 , 6, 6, 40)
SELECT StudentId, [1], [2]
FROM (
SELECT StudentId, SubjID, Test1 + Test2 + Exam AS TmpSum
FROM #ResultItems
) AS DT
PIVOT(SUM(TmpSum) FOR SubjID IN ([1], [2])) AS PT
DROP TABLE #ResultItems
SQLite solution
Use CASE
SELECT StudentId, SUM(Subj1) AS Subj1, SUM(Subj2) As Subj2
FROM (
SELECT t1.StudentId, CASE WHEN SubjID = 1 THEN Test1 + Test2 + Exam ELSE 0 END AS Subj1,
CASE WHEN SubjID = 2 THEN Test1 + Test2 + Exam ELSE 0 END AS Subj2
FROM #ResultItems AS t1
) AS T
GROUP BY T.StudentID
or subqueries:
SELECT t1.StudentId, (SELECT Test1 + Test2 + Exam FROM #ResultItems WHERE StudentID = t1.StudentID AND SubjID = 1) AS Subj1,
(SELECT Test1 + Test2 + Exam FROM #ResultItems WHERE StudentID = t1.StudentID AND SubjID = 2) AS Subj2
FROM #ResultItems AS t1
GROUP BY t1.StudentID

Order by "In clause"

I have a query wherein I use "In" clause in it.
Now I wish to have the result set in same order as my In clause.
For example -
select Id,Name from mytable where id in (3,6,7,1)
Result Set :
|Id | Name |
------------
| 3 | ABS |
| 6 | NVK |
| 7 | USD |
| 1 | KSK |
I do not want to use any temp table.
Is it possible to achieve the goal in one query?
You can use CTE as well
with filterID as
(
3 ID, 1 as sequence
union
6, 2
union
7, 3
union
1, 4
)
select mytable.* from mytable
inner join filterID on filterID.ID = mytable.ID
order by filterID.sequence ;
In T-SQL, you can do this using a big case:
select Id, Name
from mytable
where id in (3, 6, 7, 1)
order by (case id when 3 then 1 when 6 then 2 when 7 then 3 else 4 end);
Or with charindex():
order by charindex(',' + cast(id as varchar(255)) + ',',
',3,6,7,1,')