How to Order BY without having Column in SELECT - sql

I am using MS-SQL and I have a table like this:
Count Code
1 A
2 C
3 A
4 B
5 C
6 B
I need to only to get Distinct Row of the Code Column but I need to keep the Order of the Column to create a Comma Delimited String like this:
A, C, B
I have tried the following code to not get an SQL Error of Msg 145, Level 15 - ORDER BY items must appear in the select list if SELECT DISTINCT is specified.
SELECT #tlist = ISNULL(#tlist+', ','') + Code
FROM (SELECT DISTINCT t.Code
FROM #Table t)
but I get an output of A, B, C

So, you don't want distinct. You want group by:
select t.code
from #Table t
group by t.code
order by min(count)
You can order by columns not mentioned in the select clause.
To get the comma delimited list as a single variable, use this technique:
select stuff((select ', '+t.code
from #Table t
group by t.code
order by min(count)
for xml path ('')
), 1, 2, '')
Order by in a subquery is generally undefined. And, your method of concatenating the list together in order is not guaranteed to work.

order them in your subquery
SELECT DISTINCT t.Code
FROM #Table t
ORDER BY t.Code

Related

Msg 120, Level 15, State 1, Procedure Generate_Exame, Line 6,The select list for the INSERT statement contains fewer items than the insert list

I want insert in question table that has these columns
C#_T_F_Id, C#_T_F_Q, C#_T_F_Choices, C#_Mcq_Id, C#_MCQ_Q, C#_Choices
After execute Generate_Exame procedure what should I do :
create procedure Generate_Exame
#course_id int
as
if #course_id = 600
begin
insert into [dbo].[Question](C#_T_F_Id, C#_T_F_Q, C#_T_F_Choices,
C#_Mcq_Id, C#_MCQ_Q, C#_Choices)
select *
from
(select top(3)
T.C#_T_F_Id, T.C#_T_F_Q, T.C#_T_F_Choices
from
C#_T_F T
order by
newid()) as t1
union all
select *
from
(select top(7)
C.C#_Mcq_Id C#_Q_id, C.C#_MCQ_Q C#_question, C.C#_Choices Choices
from
C#_MCQ C
order by
newid()) as t2)
end
If I understand well you want to:
Insert data into a table from a combined result set.
Combine two result sets side by side. The first one provides columns 1, 2, and 3, while the second one provides column 4, 5, and 6.
On top of this both result sets (left and right) do not have the same lenght. One has 3 rows, while the other has 7 rows. I assume these numbers may vary.
There's no set order for the rows on the left, or the rows on the right. You are producing them by ordering using a random UUID, so that can change every time you run the query.
In order to do this you need to produce a row number on each side. Then a simple full join will combine both result sets.
For example:
insert into [dbo].[Question] (
C#_T_F_Id, C#_T_F_Q, C#_T_F_Choices,
C#_Mcq_Id, C#_MCQ_Q, C#_Choices
)
select -- Step #4: produce combined rows, ready for insert
a.T.C#_T_F_Id, a.T.C#_T_F_Q, a.T.C#_T_F_Choices,
b.C#_Q_id, b.C#_question, b.Choices
from ( -- Step #1: Produce the left result set with row number (rn)
select *, row_number() over(order by ord) as rn
from (
select top(3)
T.C#_T_F_Id, T.C#_T_F_Q, T.C#_T_F_Choices,
newid() as ord
from C#_T_F T
order by ord
) x
) a
full join ( -- Step #2: Produce the right result set with row number (rn)
select *, row_number() over(order by ord) as rn
from (
select top(7)
C.C#_Mcq_Id C#_Q_id, C.C#_MCQ_Q C#_question, C.C#_Choices Choices,
newid() as ord
from C#_MCQ C
order by ord
) y
) b on a.rn = b.rn -- Step #3: Full join both result sets by row number (rn)
You are having six columns in the INSERT clause. But, you have only 3 columns coming out of the UNION query.
-- You are inserting 6 columns
insert into [dbo].[Question](C#_T_F_Id, C#_T_F_Q, C#_T_F_Choices,
C#_Mcq_Id, C#_MCQ_Q, C#_Choices)
-- You are selecting only 3 columns.
select *
from
(select top(3)
T.C#_T_F_Id, T.C#_T_F_Q, T.C#_T_F_Choices
from
C#_T_F T
order by
newid()) as t1
union all
select *
from
(select top(7)
C.C#_Mcq_Id C#_Q_id, C.C#_MCQ_Q C#_question, C.C#_Choices Choices
from
C#_MCQ C
order by
newid()) as t2)
If you need to have 6 columns, you need to join the two SELECT statements in some way, based on JOIN condition.

Ambiguous Error while column name is used in order by clause

I have encountered one issue below
SELECT ColumnName1,*
FROM TableName
WHERE ColumnName = 'XXXXXX'
ORDER BY ColumnName1
From above query it throws error as Ambiguous column name Column Name1.
Even though I have not used number tables then too it throws error like this. Can anybody tell what the reason behind this.
Because the SELECT has two columns called ColumnName1 -- one placed there explicitly and one from the *. Here are some choices:
SELECT t.ColumnName1, t.*
FROM TableName t
WHERE t.ColumnName = 'XXXXXX'
ORDER BY t.ColumnName1
or:
SELECT t.ColumnName1, t.*
FROM TableName t
WHERE t.ColumnName = 'XXXXXX'
ORDER BY 1
or:
SELECT t.ColumnName1 as second_columnname1, t.*
FROM TableName t
WHERE t.ColumnName = 'XXXXXX'
ORDER BY second_columnname1
To resolve an error we have 3 options:
-- 1. give alias to the column
SELECT A AS A_STANDS_ALONE, *
FROM YourTable
ORDER BY A
-- 2. order by 1
SELECT A, *
FROM YourTable
ORDER BY 1
-- 3. give alias to the table and used it in column call and order by
SELECT t.A, *
FROM YourTable t
ORDER BY t.A

How to select all columns for rows where I check if just 1 or 2 columns contain duplicate values

I'm having difficulty with what I figure should be an easy problem. I want to select all the columns in a table for which one particular column has duplicate values.
I've been trying to use aggregate functions, but that's constraining me as I want to just match on one column and display all values. Using aggregates seems to require that I 'group by' all columns I'm going to want to display.
If I understood you correctly, this should do:
SELECT *
FROM YourTable A
WHERE EXISTS(SELECT 1
FROM YourTable
WHERE Col1 = A.Col1
GROUP BY Col1
HAVING COUNT(*) > 1)
You can join on a derived table where you aggregate and determine "col" values which are duplicated:
SELECT a.*
FROM Table1 a
INNER JOIN
(
SELECT col
FROM Table1
GROUP BY col
HAVING COUNT(1) > 1
) b ON a.col = b.col
This query gives you a chance to ORDER BY cola in ascending or descending order and change Cola output.
Here's a Demo on SqlFiddle.
with cl
as
(
select *, ROW_NUMBER() OVER(partition by colb order by cola ) as rn
from tbl)
select *
from cl
where rn > 1

Counting the rows of a column where the value of a different column is 1

I am using a select count distinct to count the number of records in a column. However, I only want to count the records where the value of a different column is 1.
So my table looks a bit like this:
Name------Type
abc---------1
def----------2
ghi----------2
jkl-----------1
mno--------1
and I want the query only to count abc, jkl and mno and thus return '3'.
I wasn't able to do this with the CASE function, because this only seems to work with conditions in the same column.
EDIT: Sorry, I should have added, I want to make a query that counts both types.
So the result should look more like:
1---3
2---2
SELECT COUNT(*)
FROM dbo.[table name]
WHERE [type] = 1;
If you want to return the counts by type:
SELECT [type], COUNT(*)
FROM dbo.[table name]
GROUP BY [type]
ORDER BY [type];
You should avoid using keywords like type as column names - you can avoid a lot of square brackets if you use a more specific, non-reserved word.
I think you'll want (assuming that you wouldn't want to count ('abc',1) twice if it is in your table twice):
select count(distinct name)
from mytable
where type = 1
EDIT: for getting all types
select type, count(distinct name)
from mytable
group by type
order by type
select count(1) from tbl where type = 1
;WITH MyTable (Name, [Type]) AS
(
SELECT 'abc', 1
UNION
SELECT 'def', 2
UNION
SELECT 'ghi', 2
UNION
SELECT 'jkl', 1
UNION
SELECT 'mno', 1
)
SELECT COUNT( DISTINCT Name)
FROM MyTable
WHERE [Type] = 1

Wrap-around in SQL results ordering

If I have a table with items beginning with C, D, and J, is it in any way possible to arrange a query that orders these ascending, but starts with D, and ends with C wrapped around?
E.g. raw table = C,C,C,D,D,J
Desired result order = D,D,J,C,C,C
In ordinary SQL this is, not any functional language? I can't see how the desired order can be achieved without hard-coding, i.e. selecting each individual record in the desired order all union'd together.
You could introduce a custom sort key with a CASE statement.
Select Col1, Col2, Col3,
case left(Col3,1) when 'D' then 1
when 'J' then 2
when 'C' then 3
else 4
end as SortKey
from YourTable
order by SortKey, Col3
That does not seem like a regular order, so you won't be able to do it in a simple way. But you can do this:
(SELECT * FROM yourtable WHERE ID >=C ORDER BY ID) UNION (SELECT SELECT * FROM yourtable WHERE ID <C ORDER BY ID)
You can implement custom sort orders without hardcoding by using a table:
CREATE TABLE SortRules (
Prefix char(1) NOT NULL
,SortOrder int NOT NULL
)
Then join to the SortRules table:
SELECT *
FROM YourTable
LEFT JOIN SortRules
ON YourTable.YourColumn LIKE SortRules.Prefix + '%'
ORDER BY SortRules.SortOrder, YourTable.YourColumn
You can make SortOrder UNIQUE (although that's not required). You can also decide if you want missing ones (unmatched in the join) to be at the top or bottom:
SELECT *
FROM YourTable
LEFT JOIN SortRules
ON YourTable.YourColumn LIKE SortRules.Prefix + '%'
ORDER BY COALESCE(SortRules.SortOrder, 2147483647), YourTable.YourColumn
SELECT *
FROM YourTable
LEFT JOIN SortRules
ON YourTable.YourColumn LIKE SortRules.Prefix + '%'
ORDER BY COALESCE(SortRules.SortOrder, -2147483648), YourTable.YourColumn