Is there any way to order the result (for example)
SELECT id,age, Location
FROM Student
WHERE Location in ('NY','DC','MI','TE')
instead of having them as
id age Location
1 2 DC
2 2 NY
4 2 MI
6 2 TE
The Result should be ordered as the order of in ('NY','DC','MI','TE'):
id age Location
2 2 NY
1 2 DC
4 2 MI
6 2 TE
I figured that It's possible by having a temp table and inserting the ('NY','DC','MI','TE') into this table. Then using a left join will order it as wanted.
Is there a better solution.
Please Advise.
In MySQL this can be done using FIND_IN_SET, which gives back the index of the occurrence of the first argument in the second, the latter being a string containing comma-separated values.
I think the same thing should be possible using CHARINDEX - give this a try:
SELECT id, age, location
FROM student
WHERE location IN ('NY','DC','MI','TE')
ORDER BY CHARINDEX (location, 'NY,DC,MI,TE')
Any solution would be roughly the equivalent of using a temp table. You could use a CTE or a subquery, but you are essentially using different syntax to perform the same operation.
Assuming you don't have to select city codes from a table, try some of the following:
ORDER BY FIELD(Location,'NY','DC','MI','TE')
ORDER BY FIND_IN_SET(Location,'NY,DC,MI,TE')
ORDER BY LOCATE(CONCAT(',',Location,','),',NY,DC,MI,TE,')
ORDER BY Location IN ('NY','DC','MI','TE')
IN could also accept a sub-query (ORDER BY Location IN SELECT city_code FROM ...)
Related
In SQL Server, how can I convert one single row of integer data, like this
ColumnName1 ColumnName2 ColumnName3
1 2 3
into a single row, order by DSEC?
ColumnNameTotalSort
3
2
1
I know the requirement seems simple but I have been struggling for a while.
Thanks for input.
As ZLK mentioned, UNPIVOT is an option
Another option is with a CROSS APPLY and VALUES
Example
Select B.*
From YourTable A
Cross Apply (values (ColumnName1)
,(ColumnName2)
,(ColumnName3)
) B(ColumnNameTotalSort)
-- Where Your Filter Condition Here
Order By ColumnNameTotalSort Desc
Returns
ColumnNameTotalSort
3
2
1
I have a table that has a new column, and updating the values that should go in the new column. For simplicity sake I am reducing my example table structure as well as my query. Below is how i want my output to look.
IDNumber NewColumn
1 1
2 1
3 1
4 2
5 2
WITH CTE_Split
AS
(
select
*,ntile(2) over (order by newid()) as Split
from TableA
)
Update a
set NewColumn = a.Split
from CTE_Split a
Now when I do this I get my table and it looks as such
IDNumber NewColumn
1 1
2 1
3 1
4 1
5 1
However when I do the select only I can see that I get the desire output, now I have done this before to split result sets into multiple groups and everything works within the select but now that I need to update the table I am getting this weird result. Not quiet sure what I'm doing wrong or if anyone can provide any sort of feedback.
So after a whole day of frustration I was able to compare this code and table to another that I had already done this process to. The reason that this table was getting updated to all 1s was because turns out that whoever made the table thought this was supposed to be a bit flag. When it reality it should be an int because in this case its actually only two possible values but in others it could be more than two.
Thank you for all your suggestion and help and it should teach me to scope out data types of tables when using the ntile function.
Try updating your table directly rather than updating your CTE. This makes it clearer what your UPDATE statement does.
Here is an example:
WITH CTE_Split AS
(
SELECT
*,
ntile(2) over (order by newid()) as Split
FROM TableA
)
UPDATE a
SET NewColumn = c.Split
FROM
TableA a
INNER JOIN CTE_Split c ON a.IDNumber = c.IDNumber
I assume that what you want to achieve is to group your records into two randomized partitions. This statement seems to do the job.
I am looking to retrieve only the second (duplicate) record from a data set. For example in the following picture:
Inside the UnitID column there is two separate records for 105. I only want the returned data set to return the second 105 record. Additionally, I want this query to return the second record for all duplicates, not just 105.
I have tried everything I can think of, albeit I am not that experience, and I cannot figure it out. Any help would be greatly appreciated.
You need to use GROUP BY for this.
Here's an example: (I can't read your first column name, so I'm calling it JobUnitK
SELECT MAX(JobUnitK), Unit
FROM JobUnits
WHERE DispatchDate = 'oct 4, 2015'
GROUP BY Unit
HAVING COUNT(*) > 1
I'm assuming JobUnitK is your ordering/id field. If it's not, just replace MAX(JobUnitK) with MAX(FieldIOrderWith).
Use RANK function. Rank the rows OVER PARTITION BY UnitId and pick the rows with rank 2 .
For reference -
https://msdn.microsoft.com/en-IN/library/ms176102.aspx
Assuming SQL Server 2005 and up, you can use the Row_Number windowing function:
WITH DupeCalc AS (
SELECT
DupID = Row_Number() OVER (PARTITION BY UnitID, ORDER BY JobUnitKeyID),
*
FROM JobUnits
WHERE DispatchDate = '20151004'
ORDER BY UnitID Desc
)
SELECT *
FROM DupeCalc
WHERE DupID >= 2
;
This is better than a solution that uses Max(JobUnitKeyID) for multiple reasons:
There could be more than one duplicate, in which case using Min(JobUnitKeyID) in conjunction with UnitID to join back on the UnitID where the JobUnitKeyID <> MinJobUnitKeyID` is required.
Except, using Min or Max requires you to join back to the same data (which will be inherently slower).
If the ordering key you use turns out to be non-unique, you won't be able to pull the right number of rows with either one.
If the ordering key consists of multiple columns, the query using Min or Max explodes in complexity.
May I know is there any solution to get the result without ordering in Oracle? It is because when I execute the query as follows, it seems to automatically helps me to sort it by ID field.
SELECT ID FROM USER WHERE ID IN (5004, 5003, 5005, 5002, 5008);
Actual results Expected results
---5002 ---5004
---5003 ---5003
---5004 ---5005
---5005 ---5002
---5008 ---5008
Million thanks if you guys have solutions on this.
SELECT statements return the rows of their result sets in an unpredictable order unless you give an ORDER BY clause.
Certain DBMS products give the illusion that their result sets are in a predictable order. But if you rely on that you're bound to be disappointed.
This is one way I've seen in the past using INSTR:
SELECT *
FROM YourTable
WHERE ID IN (5004, 5003, 5005, 5002, 5008)
ORDER BY INSTR ('5004,5003,5005,5002,5008', id)
SQL Fiddle Demo
I've also seen use of CASE like this:
ORDER BY
CASE ID
WHEN 5004 THEN 1
WHEN 5003 THEN 2
WHEN 5005 THEN 3
WHEN 5002 THEN 4
WHEN 5008 THEN 5
END
if you want to keep the order as your in list, you can do something like this:
SQL> create type user_va as varray(1000) of number;
2 /
Type created.
SQL> with users as (select /*+ cardinality(a, 10) */ rownum r, a.column_value user_id
2 from table(user_va(11, 0, 19, 5)) a)
3 select d.user_id, d.username
4 from dba_users d
5 inner join users u
6 on u.user_id = d.user_id
7 order by u.r
8 /
USER_ID USERNAME
---------- ------------------------------
11 OUTLN
0 SYS
19 DIP
5 SYSTEM
i.e we put the elements into a varray and assign a rownum prior to merging the set. we can then order by that r to maintain the order of our in list. The cardinality hint just tells the optimizer how many rows are in the array (doesn't have to be dead on, just in the ballpark..as without this, it will assume 8k rows and may prefer a full scan over an index approach)
if you don't have privs to create a type and this is just some adhoc thing, there's a few public ones:
select owner, type_name, upper_bound max_elements, length max_size, elem_type_name
from all_Coll_types
where coll_type = 'VARYING ARRAY'
and elem_type_name in ('INTEGER', 'NUMBER');
There is no guarantee of sort order without an ORDER BY clause.
If your question is about why the ordering occurs then the answer is: Do you have an index or primary key defined on the column ID? If yes the database responds to your query with an index scan. That is: it looks up the IDs in the IN clause not in the table itself but in the index defined on your ID-column. Within the index the values are ordered.
To get more information about the execution of your query try Oracle's explain plan feature.
To get the values in a certain order you have to add an ORDER BY clause. One way of doing this would be
select ID
from USER
where ID in (5004, 5003, 5005, 5002, 5008)
order by
case ID
when 5004 then 1
when 5003 then 2
...
end;
A more general way would be to add an ORDERING column to your table:
select ID
from USER
where ID in (5004, 5003, 5005, 5002, 5008)
order by
ORDERING;
Another solution that I found here.
select ID
from USER
where ID in (5004, 5003, 5005, 5002, 5008)
order by decode(ID, 5002, 1, 5003, 2, 5004, 3, 5005, 4, 5008, 5);
order by decode(COLUMN NAME, VALUE, POSITION)
*Note: Only need to repeat the VALUE and POSITION
And yah, thanks for all the responds! I am really appreciate it.
How can I show the number of rows in a table in a way that when a new record is added the number representing the row goes higher and when a record is deleted the number gets updated accordingly?
To be more clear,suppose I have a simple table like this :
ID int (primary key) Name varchar(5)
The ID is set to get incremented by itself (using identity specification) so it can't represent the number of row(record) since if I have for example 3 records as:
ID NAME
1 Alex
2 Scott
3 Sara
and I delete Alex and Scott and add a new record it will be:
3 Sara
4 Mina
So basically I'm looking for a sql-side solution for doing this so that I don't change anything else in the source code in multiple places.
I tried to write something to get the job done but it failes. Here it is :
SELECT COUNT(*) AS [row number],Name
FROM dbo.Test
GROUP BY ID, Name
HAVING (ID = ID)
This shows as:
row number Name
1 Alex
1 Scott
1 Sara
while I want it to get shown as:
row number Name
1 Alex
2 Scott
3 Sara
If you just want the number against the rows while selecting the data and not in the database then you can use this
select row_number() over(order by id) from dbo.Test
This will give the row number n for nth row.
Try
SELECT id, name, ROW_NUMBER() OVER (ORDER BY id) AS RowNumber
FROM MyTable
What you want is called an auto increment.
For SQL-Server this is achieved by adding the IDENTITY(1,1) attribute to the table definition.
Other RDBMS use a different syntax. Firebird for example has generators, which do the counting. In a BEFORE-INSERT trigger you would assign the ID-field to the current value of the generator (which will be increased automatically).
I had this exact problem a while ago, but I was using SQL Server 2000, so although row number() is the best solution, in SQL Server 2000, this isn't available. A workaround for this is to create a temporary table, insert all the values with auto increment, and replace the current table with the new table in T-SQL.