I have this column in my table and I want to get all skipped transactions (which is a varchar)
SA1
SA3
SA50
SA999
I'm trying to get
SA2
SA4 to SA49
SA51 to SA998
EDIT: I've checked the actual data, found out that it's non-trailing zeroes.
I've done this with PHP. Was wondering if is there a way within SQL to do it?
This might sound dumb, but what I'm trying is to plot it like this (this returns null values)
WITH cte (id) AS (
SELECT ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_columns AS s1
CROSS JOIN sys.all_columns AS s2
),
table1 AS (
SELECT sNumber as id1 FROM Sales WHERE sNumber LIKE '%SI_'
),
table2 AS (
SELECT sNumber as id1 FROM Sales WHERE sNumber LIKE '%SI__'
),
table3 AS (
SELECT sNumber as id1 FROM Sales WHERE sNumber LIKE '%SI___'
)
SELECT
'SA' + RIGHT('' + CAST(t1.id AS VARCHAR(2)), 1) AS id_missing
FROM cte t1
LEFT JOIN table1 t2
ON t1.id = CAST(RIGHT(t2.id1, 1) AS INT)
WHERE
t1.id < (SELECT MAX(CAST(RIGHT(id1, 1) AS INT)) FROM yourTable1) AND
t2.id1 IS NULL
UNION ALL
SELECT
'SA' + RIGHT('' + CAST(t1.id AS VARCHAR(2)), 2) AS id_missing
FROM cte t1
LEFT JOIN table2 t2
ON t1.id = CAST(RIGHT(t2.id2, 2) AS INT)
WHERE
t1.id < (SELECT MAX(CAST(RIGHT(id2, 2) AS INT)) FROM yourTable2) AND
t2.id2 IS NULL
UNION ALL
SELECT
'SA' + RIGHT('' + CAST(t1.id AS VARCHAR(3)), 3) AS id_missing
FROM cte t1
LEFT JOIN table3 t2
ON t1.id = CAST(RIGHT(t2.id3, 3) AS INT)
WHERE
t1.id < (SELECT MAX(CAST(RIGHT(id3, 3) AS INT)) FROM yourTable3) AND
t2.id3 IS NULL
You may use a calendar table approach with a left join here:
WITH cte (id) AS (
SELECT ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_columns AS s1
CROSS JOIN sys.all_columns AS s2
)
SELECT
'SA' + RIGHT('000' + CAST(t1.id AS VARCHAR(3)), 3) AS id_missing
FROM cte t1
LEFT JOIN yourTable t2
ON t1.id = CAST(RIGHT(t2.id, 3) AS INT)
WHERE
t1.id < (SELECT MAX(CAST(RIGHT(id, 3) AS INT)) FROM yourTable) AND
t2.id IS NULL;
Demo
The idea is to generate a sequence of numbers covering the possible up to 1000 values which might appear in your current table as SAxxx. Then, we left join this calendar table to your current table, on the condition that the numeric portion of the id does not match. All such non matching SAxxx values are then retained in the result set.
Related
I received this answer to this question MS SQL Server Last User Logged in Multiple Clients with Multiple Users and it works great.
;with cte as
(
select
client, myuser, lastlogin,
row_number() over (partition by client order by lastlogin desc) r#
from
#mytable
)
select *
from cte
where r# = 1
How do I get this joined to a regular Select statement that selects data from other tables also?
For example:
SELECT t1.id, t2.name
FROM table1 t1
JOIN table2 t2 ON (t2.id = t1.id)
WHERE t1.id = 1
There is no restriction, you can just join a result of a cte with other tables. Cte is a subquery, but it makes your code more readable.
;with cte as(
select client,myuser,lastlogin,row_number() over(partition by client order by lastlogin desc) r#
from #mytable
)
SELECT t1.id, t2.name
FROM table1 t1
JOIN table2 t2 ON (t2.id = t1.id)
JOIN cte t3 ON (...)
WHERE t1.id = 1
This is the same as a query with cte.
SELECT t1.id, t2.name
FROM table1 t1
JOIN table2 t2 ON (t2.id = t1.id)
JOIN ( select client,myuser,lastlogin,row_number() over(partition by client order by lastlogin desc) r#
from #mytable) t3 ON (...)
WHERE t1.id = 1
I am trying to Left join Table 1 to table 2
Table1 Table2
ID Data ID Data2
1 r 1 q
2 t 1 a
3 z 2 x
1 u 3 c
After i have left joined this two Tables i would like get something like this
Table1+2
ID Data Data2
1 r a
2 t x
3 z c
1 u q
and NOT
Table1+2
ID Data Data2
1 r q
2 t x
3 z c
1 u q
and my question is: is there any possibility to tell table 2 that if u have used something for table 1, dont use it and give me next value. do i have to make it im T-SQL or to and new column where i can list if this id exists then write 2 if not 1(Number data). How can i solve this problem?
Ty u in advance.
Since there's no uniqueness in the ID on both tables, lets add some uniqueness to it.
So it can be used to join on.
The window function ROW_NUMBER can be used for that.
An example solution that gives the expected result:
DECLARE #TestTable1 TABLE (ID INT, Data VARCHAR(1));
DECLARE #TestTable2 TABLE (ID INT, Data VARCHAR(1));
INSERT INTO #TestTable1 VALUES (1,'r'),(2,'t'),(3,'z'),(1,'u');
INSERT INTO #TestTable2 VALUES (1,'q'),(1,'a'),(2,'x'),(3,'c');
select
t1.ID, t1.Data,
t2.Data as Data2
from (
select ID, Data,
row_number() over (partition by ID order by Data) as rn
from #TestTable1
) t1
left join (
select ID, Data,
row_number() over (partition by ID order by Data) as rn
from #TestTable2
) t2 on t1.ID = t2.ID and t1.rn = t2.rn;
Note: Because of the LEFT JOIN, this does assume the amount of same ID's in table2 are equal or lower can those on table1. But you can change that to a FULL JOIN if that's not the case.
Returns :
ID Data Data2
1 r a
1 u q
2 t x
3 z c
To get the other result could have been achieved in different ways.
This is actually a more common situation.
Where one wants all from Table 1, but only get one value from Table 2 for each record of Table 1.
1) A top 1 with ties in combination with a order by rownumber()
select top 1 with ties
t1.ID, t1.Data,
t2.Data as Data2
from #TestTable1 t1
left join #TestTable2 t2 on t1.ID = t2.ID
order by row_number() over (partition by t1.ID, t1.Data order by t2.Data desc);
The top 1 with ties will only show those where the row_number() = 1
2) Using the row_number in a subquery:
select ID, Data, Data2
from (
select
t1.ID, t1.Data,
t2.Data as Data2,
row_number() over (partition by t1.ID, t1.Data order by t2.Data desc) as rn
from #TestTable1 t1
left join #TestTable2 t2 on t1.ID = t2.ID
) q
where rn = 1;
3) just a simple group by and a max :
select t1.ID, t1.Data, max(t2.Data) as Data2
from #TestTable1 t1
left join #TestTable2 t2 on t1.ID = t2.ID
group by t1.ID, t1.Data
order by 1,2;
All 3 give the same result:
ID Data Data2
1 r q
1 u q
2 t x
3 z c
Use ROW_NUMBER
DECLARE #Table1 TABLE (ID INT, DATA VARCHAR(10))
DECLARE #Table2 TABLE (ID INT, DATA VARCHAR(10))
INSERT INTO #Table1
VALUES
(1, 'r'),
(2, 't'),
(3, 'z'),
(1, 'u')
INSERT INTO #Table2
VALUES
(1, 'q'),
(1, 'a'),
(2, 'x'),
(3, 'c')
SELECT
A.*,
B.DATA
FROM
(SELECT *, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY(SELECT NULL)) RowId FROM #Table1) A INNER JOIN
(SELECT *, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY(SELECT NULL)) RowId FROM #Table2) B ON A.ID = B.ID AND
A.RowId = B.RowId
I have a Select with sub selects using Top 1 and where clause.
I tried to optimize the select by doing a Left Join of the sub selects but the query time took longer. Is subselect better in this case? I couldnt post my whole select because it is too long and confidential but I will try to recreate the important part below:
Sub Select
SELECT
(select top 1 colId FROM table1 WHERE col1 = b.Id and col2 = 3 Order by 1) Id3,
(select top 1 colId FROM table1 WHERE col1 = b.Id and col2 = 5 Order by 1) Id5,
(select top 1 colId FROM table1 WHERE col1 = b.Id and col2 = 7 Order by 1) Id7
FROM table2 b
Trying it w/ Left Join
SELECT
t1.colid id3,
t2.colid id5,
t3.colid id7
FROM table2 b
LEFT JOIN (
select colId, col1 FROM table1 WHERE col2 = 3
) t1 ON t1.col1 = b.Id
LEFT JOIN (
select colId, col1 FROM table1 WHERE col2 = 5
) t2 ON t1.col1 = b.Id
LEFT JOIN (
select colId, col1 FROM table1 WHERE col2 = 7
) t3 ON t1.col1 = b.Id
Is there a better way to do this? and why is it the Left join takes longer query time?
You can use ROW_NUMBER:
;WITH cte AS
(
SELECT a.colId,
rn = ROWN_NUMBER() OVER (PARTITION BY a.col2 ORDER BY a.col1)
FROM table1 a
LEFT JOIN table2 b on a.col1 = b.id
WHERE a.col2 IN (3,5,7)
)
SELECT *
FROM cte
WHERE rn = 1
This will give you the first row for each col2 value and you can restrict the values you want to 3,5,7.
Having 2 tables with the same structure, like this SQLFiddle, is it possible to build a SQL statement that compares the values of the columns of both tables (where id is the unique key), and return a list of the change columns in the format:
columnname, oldvalue, newvalue
Where oldvalue is the value in Table1 and newvalue is the value in Table2.
You can do something like this:
SELECT T1.Id
,'Name' AS ColumnName
,CAST(T1.name AS VARCHAR(MAX)) AS OldValue
,CAST(T2.name AS VARCHAR(MAX)) AS NewValue
FROM Table1 AS T1
FULL OUTER JOIN Table2 AS T2
ON T1.id = T2.id
UNION
SELECT T1.Id
,'Amount'
,CAST(T1.amount AS VARCHAR(MAX))
,CAST(T2.amount AS VARCHAR(MAX))
FROM Table1 AS T1
FULL OUTER JOIN Table2 AS T2
ON T1.id = T2.id
You need to use a MERGE statement , please note it is only available from SQL 2008 onwards
here is an example
MERGE Production.ProductInventory AS target
USING (SELECT ProductID, SUM(OrderQty) FROM Sales.SalesOrderDetail AS sod
JOIN Sales.SalesOrderHeader AS soh
ON sod.SalesOrderID = soh.SalesOrderID
AND soh.OrderDate = #OrderDate
GROUP BY ProductID) AS source (ProductID, OrderQty)
ON (target.ProductID = source.ProductID)
WHEN MATCHED AND target.Quantity - source.OrderQty <= 0
THEN DELETE
WHEN MATCHED
THEN UPDATE SET target.Quantity = target.Quantity - source.OrderQty,
target.ModifiedDate = GETDATE()
OUTPUT $action, Inserted.ProductID, Inserted.Quantity, Inserted.ModifiedDate, Deleted.ProductID,
Deleted.Quantity, Deleted.ModifiedDate;
GO
you can learn more about merge's here SQL merge
if you only want rows with differences:
SELECT COALESCE(T1.Id, T2.Id) Id
,'Name' AS ColumnName
,CAST(T1.name AS VARCHAR(MAX)) AS OldValue
,CAST(T2.name AS VARCHAR(MAX)) AS NewValue
FROM Table1 AS T1
FULL OUTER JOIN Table2 AS T2
ON T1.id = T2.id
WHERE COALESCE(T1.name,'**') != COALESCE(T2.name ,'**')
UNION ALL
SELECT COALESCE(T1.Id, T2.Id) Id
,'Amount' AS ColumnName
,CAST(T1.Amount AS VARCHAR(MAX)) AS OldValue
,CAST(T2.Amount AS VARCHAR(MAX)) AS NewValue
FROM Table1 AS T1
FULL OUTER JOIN Table2 AS T2
ON T1.id = T2.id
WHERE COALESCE(T1.Amount,0) != COALESCE(T2.Amount,0)
How to get a running total based on range:
name, Level, value, runningtotal;
A 5 5;
B 1 3 10;
B 2 2 10;
C 1 11;
I can't tell what column you are doing your running total on. But in 2008 the best way of doing a running total is a self join like this:
CREATE TABLE #Test(
ID INT NOT NULL PRIMARY KEY,
AValue INT NOT NULL)
INSERT INTO #Test VALUES (1,4), (2,2), (3,18)
SELECT T1.ID, T1.AValue, SUM(T2.AValue) RunningTotal
FROM #Test T1
JOIN #Test T2 ON T1.ID >= T2.ID
GROUP BY T1.ID, T1.AValue
DROP TABLE #Test
with cte(name,value) as
(
select name,sum(value) as val from A group by name
)
,
cte2 as
(
SELECT c.name,SUM(b.value) as val
FROM cte c inner join
cte b
on b.name <= c.name
GROUP BY c.name
)
select c.name,c.value,b.val from A c inner join cte2 b on c.name=b.name
order by c.name