Place a certain row first in ORDER BY - sql-server

I want to change the order of the records resulted from a select.
I want a certain record to be the first in my list, and the other ones after.

ORDER BY CASE WHEN col = 'something' -- whatever identifies "a certain row"
THEN 1 ELSE 2 END,
col;

You can use CASE in ODRER BY
SELECT Col1, Col2
FROM Table
ORDER BY
CASE WHEN Col1 = #certainrecord THEN 0 ELSE 1 END
, Col1
, Col2

Related

How to derive column value based on occurrence of a phrase in Snowflake

I have input table as below
I want to have a derived column with the logic like
If for single value of COL1, if field COL2 has 'ABC' then DERIVED_COL will be filled with 'ABC_FIXED', if for a single value of COL2, if field COL# does not have 'ABC', then DERIVED_COL will be filled with 'ABC_NONFIXED'.
Is this possible in Snowflake?
Just do a self-join with a subset of same table with col2='ABC'. If join produces result means ABC fixed else ABC not fixed.
select orig.col1,orig.col2,
case when abc.col2 is not null then 'ABC_FIXED' else 'ABC_NOTFIXED' end derived_col
from mytable orig
left join (select distinct col1, col2 from mytable where col2='ABC') abc
on abc.col1=orig.col1
Using windowed function:
SELECT *, CASE WHEN COUNT_IF(COL2 = 'ABC') OVER(PARTITION BY COL1) > 0
THEN 'ABC_FIXED' ELSE 'ABC_NOTFIXED'
END AS DERIVED_COL
FROM tab;

Distinct on one column with additional criteria to select non-unique rows

Okay, I know a lot of variations on this question have been asked, but here I go.
I'm starting with this query.
SELECT lprArchived, lprReportId, lprOwner
FROM ReportIndex
WHERE lprArchived = 1
In most cases, each row returned will have a unique value in the lprReportId column. However, for cases where multiple rows have the same value in lprReportId, I only want one row.
So which one? I would prefer the row where lprOwner = 'ABCD'.
Is it possible to write a query that would return unique rows and, in cases where rows were not unique, give me the one that has lprOwner = 'ABCD'?
Note: I believe that only one row will match lprOwner = 'ABCD' for a given lprReportId, but if for some reason there was more than one, I'd still only want one row returned.
Try this:
It will take one record per lprReportId and in cases where there are multiple entries with the same lprReportId, it will prioritise ones that have an lprOwner = 'ABCD'
SELECT t.Archived, t.ReportID, t.[Owner]
FROM (
SELECT
ROW_NUMBER() OVER ( PARTITION BY lprReportId ORDER BY lprReportId, CASE WHEN lprOwner = 'ABCD' THEN 1 ELSE 10 END ) AS RowNum,
lprArchived AS Archived,
lprReportId AS ReportID,
lprOwner AS [Owner]
FROM
ReportIndex
WHERE
lprArchived = 1
) t
WHERE t.RowNum = 1
select top 1
lprArchived,
lprReportId,
lprOwner
from ReportIndex
where
lprArchived = 1
order by case when lprOwner = 'ABCD' then 0 else 1 end asc
This will take all matches, order them with 'ABCD' at the top, and then take the first row. If you have any other criteria for selecting rows, you could add it to the end of the order by clause (most recent, for example).

T-SQL Selecting TOP 1 In A Query With Aggregates/Groups

I'm still fairly new to SQL. This is a stripped down version of the query I'm trying to run. This query is suppose to find those customers with more than 3 cases and display either the top 1 case or all cases but still show the overall count of cases per customer in each row in addition to all the case numbers.
The TOP 1 subquery approach didn't work but is there another way to get the results I need? Hope that makes sense.
Here's the code:
SELECT t1.StoreID, t1.CustomerID, t2.LastName, t2.FirstName
,COUNT(t1.CaseNo) AS CasesCount
,(SELECT TOP 1 t1.CaseNo)
FROM MainDatabase t1
INNER JOIN CustomerDatabase t2
ON t1.StoreID = t2.StoreID
WHERE t1.SubmittedDate >= '01/01/2017' AND t1.SubmittedDate <= '05/31/2017'
GROUP BY t1.StoreID, t1.CustomerID, t2.LastName, t2.FirstName
HAVING COUNT (t1.CaseNo) >= 3
ORDER BY t1.StoreID, t1.PatronID
I would like it to look something like this, either one row with just the most recent case and detail or several rows showing all details of each case in addition to the store id, customer id, last name, first name, and case count.
Data Example
For these I usually like to make a temp table of aggregates:
DROP TABLE IF EXISTS #tmp;
CREATE TABLE #tmp (
CustomerlD int NOT NULL DEFAULT 0,
case_count int NOT NULL DEFAULT 0,
case_max int NOT NULL DEFAULT 0,
);
INSERT INTO #tmp
(CustomerlD, case_count, case_max)
SELECT CustomerlD, COUNT(tl.CaseNo), MAX(tl.CaseNo)
FROM MainDatabase
GROUP BY CustomerlD;
Then you can join this "tmp" table back to any other table you want to display the number of cases on, or the max case number on. And you can limit it to customers that have more than 3 cases with WHERE case_count > 3

Inserting value into target table dervived column from source table value with an IF ELSE statement

I'm trying to import from a staging table(source) to a destination table(dest) in SQL Server. Some of the destination table values are derived from the source table values based on a conditional statement. The logic is somewhat like this
IF source.col1=0
BEGIN
IF source.col2=0
BEGIN
dest.colA = 1
dest.colB = source.col3
END
ELSE
BEGIN
dest.colC= 1
dest.colD= source.col3
END
ELSE IF source.col4>0
BEGIN
dest.colD=1
dest.colE=source.col3
END
ELSE
BEGIN
dest.colF=1
dest.colG=source.col1
END
END
I am currently doing a merge from source table to destination table within a stored procedure and have other columns besides the above that map perfectly. How can i write this logic such that the destination table derived columns are set from source table columns based on the logic above? None of what I have tried so far works or makes sense to me. Thank you in advance for your help
Thank you M. Ali and phiosophicles. I am using this in a merge statement but now I am getting the error Invalid object name 'Source'.
I am not getting this error on any of my other merge statements. Source is below. I have anonymized to a certain extent so please let me know if it isn't clear
MERGE dbo.Destination WITH (HOLDLOCK) AS Target
USING
(
SELECT DISTINCT id, col3,
CAST(LEFT(DATEADD(m,months,CONVERT(date,CONCAT(origination,'/01'))),7) as varchar(20)) as CalendarMonth,
col1, col2,col4 FROM dbo.Staging
) AS Source
ON (Target.ID=Source.id
AND Target.Month=Source.col3)
WHEN MATCHED THEN
UPDATE SET
Target.CalendarMonth=Source.CalendarMonth,
Target.colF= (SELECT CASE WHEN col1>0 THEN 1 END AS colF FROM Source),
Target.colD=(SELECT CASE WHEN col4>0 THEN 1 END AS colD
FROM Source),
Target.colC=(SELECT CASE WHEN col1=0 AND col2=0
THEN 1 END AS colC FROM Source),
Target.colB(SELECT CASE WHEN col1>0 AND col2
THEN 1 END AS colB FROM Source),
Target.colG=(SELECT CASE WHEN col1>0 THEN col1 END AS colG FROM Source),
Target.colE=(SELECT CASE WHEN col4>0 THEN col3 END
AS colE FROM Source),
Target.PaidMonth=(SELECT CASE WHEN col1=0 AND col2=0
THEN col3 END AS PaidMonth
FROM Source),
WHEN NOT MATCHED BY TARGET THEN
INSERT
(Destination Table columns
)
VALUES
( Source values including derived values from above);
END
GO
UPDATE:
I replaced the select statement in the derived columns with CASE WHEN col4>0 THEN col3 END and so on which got rid of the error. Thanks everyone for your help!
T-SQL has two very different language constructs that both relate to "if one thing is true, do this, else that".
The IF/BEGIN/END construct demonstrated in the question is exclusively for flow control in T-SQL; that is, it should be used to wrap around whole blocks of code to control whether they are executed at all or not. You can put any SELECT, INSERT, UPDATE or DELETE query inside the BEGIN/END of an IF construct; you can also put data definition code (for example CREATE TABLE), variable assignment, and many other kinds of statement.
What you are trying to do, on the other hand, is control which column expression should be presented. This has to be done within a query (a SELECT, INSERT or UPDATE), and therefore uses a different T-SQL construct, CASE..END. M.Ali has provided a great example of how to use CASE..END in his answer, so I won't duplicate that. Just notice that each CASE..END block takes the place of a column in the SQL query.
INSERT INTO Destination (ColA, ColB, ColC, ColD, ColF, ColG)
Select CASE WHEN Col1 = 0 AND Col2 = 0 THEN 1 END AS ColA
,CASE WHEN Col1 = 0 AND Col2 = 0 THEN Col3 END AS ColB
,CASE WHEN Col1 = 0 AND Col2 <> 0 THEN 1 END AS ColC
,CASE WHEN Col1 = 0 AND Col2 <> 0 THEN Col3
WHEN Col1 <> 0 AND Col4 > 0 THEN 1 END AS ColD
,CASE WHEN Col1 <> 0 AND Col4 !> 0 THEN 1 END AS ColF
,CASE WHEN Col1 <> 0 AND Col4 !> 0 THEN Col1 END AS ColG
FROM SourceTable

Aggregate Function Error on an Expression

What could be wrong with this query:
SELECT
SUM(CASE
WHEN (SELECT TOP 1 ISNULL(StartDate,'01-01-1900')
FROM TestingTable
ORDER BY StartDate Asc) <> '01-01-1900' THEN 1 ELSE 0 END) AS Testingvalue.
The get the error:
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
As koppinjo stated what your current (broken) query is doing is checking if you have a NULL-value (or StartDate = '01-01-1900') in your table, return either a 1 or a 0 depending on which, and then attempting to SUM that single value.
There are 2 different logical things you want.
Either getting the amount of rows that has a StartDate or checking if any row is missing StartDate.
SELECT --Checking if there is a NULL-value in table
(
CASE WHEN
(SELECT TOP 1 ISNULL(StartDate,'01-01-1900')
FROM TestingTable
ORDER BY StartDate Asc) <> '01-01-1900' THEN 1
ELSE 0
END
) AS TestingValue
SELECT SUM(TestingValue) TestingValue --Give the count of how many non-NULLs there is
FROM
(
SELECT
CASE WHEN
ISNULL(StartDate,'01-01-1900') <> '01-01-1900' THEN 1
ELSE 0
END AS TestingValue
FROM TestingTable
) T
Here is a SQL Fiddle showing both outputs side by side.
Hard to say, but you probably want something like this:
SELECT
SUM(TestingValue)
FROM
(SELECT
CASE
WHEN ISNULL(StartDate,'01-01-1900') <> '01-01-1900'
THEN 1
ELSE 0
END AS TestingValue
FROM TestingTable) t
As your original query is written now, your subquery will return 1 value overall, so your sum would be 1 or 0 always, not to mention it is illegal. To get around that, this SQL will apply the case statement to every row in the TestingTable and insert the result into a derived table (t), then the 'outer' select will sum the results. Hope this helps!

Resources