Sql create table with alternate row from two different table - sql-server

I'm having two table which contain data for reviler for employee on shift basis
e.g
Table 1
------
ID NAME RELIVERID
------------
20 ABC 56
----------
21 XYZ 57
----------
22 DEF 58
----------
TABLE 2
---------
ID NAME RELIVERID
-------
56 PQR 20
-----
57 STU 21
-----
58 XYZ 21
----
I want result in third table with following data
Result Table
-------
ID NAME RELIVERID
---
20 ABC 56
-
56 PQR 20
-
21 XYZ 57
-
57 STU 21
-
22 DEF 58
-
58 XYZ 21
-
1 row from first table and alternate row from second table

My suggestion is to use the row_number function, multiply it with a factor for the 1st table and for the second table add 1 so it will be greater than the one in the 1st table and perform an union all. I don't a SQL Server instance to test this, but it should be something like this:
SELECT (ROW_NUMBER() OVER (ORDER BY ID ASC)) * 100 AS OrderID, * FROM Table1
UNION ALL
SELECT (ROW_NUMBER() OVER (ORDER BY ID ASC)) * 100 + 1 AS OrderID, * FROM Table2
ORDER BY OrderID

Related

Update A column based on values in B column

Let's say I have Table1, and Table2 like below:
Table1
Nmae ColA ColB
---------------
Peter 25
Jason 52
Tom 74
Jim 65
Table2
Values Prize
-------------
25 ABC
50 ABC1
75 ABC2
100 ABC3
Now I want to update ColB in Table1 based on the values in ColA.
e.g. If value >= 25 and < 50 then ABC. If value >= 50 and < 75 then ABC1.
Desired output:
Name ColA ColB
----------------
Peter 25 ABC
Jason 52 ABC1
Tom 76 ABC2
Jim 65 ABC1
I've tried to solve the problem by joining two tables to update ColB but got stuck. I know this can be easily done by using CASE WHEN. However, I'm worried that going forward if the rules change or what, I have to modify the code in multiple SPs.
You can easily do that UPDATE using a subquery instead of a CASE WHEN
update table1 set ColB = (select top 1 Prize
from table2
where Values <= ColA order by Values desc)

SQL - Select non repeating columns

I have a table like
id name R_id mgr_id
----------------------------
61 a 22 1
62 a 22 2
62 b 23 1
63 c 24 4
63 b 22 3
64 c 25 3
and I would like to get the following result set
R_id mgr_id
--------------
22 1
23 1
24 4
25 3
I would like select repeating R_ids only once
I tried using this query but with not much success, can anyone help me.
SELECT DISTINCT R_id, mgr_id from DT
Perhaps something like this... WITH TIES clause in concert with Row_NUmber()
Example
Select Top 1 with ties
R_ID
,mgr_id
From #YourTable
Order By Row_Number() over (Partition By R_ID order by Mgr_id)
Returns
R_ID mgr_id
22 1
23 1
24 4
25 3

Postgresql select top 5 marks rows for every unique student id

This is one of my views called xyz:
ID | NAME |......Other Data... | Marks
1 A 100
1 A 100
1 A 99
1 A 95
1 A 94
1 A 94
1 A 94
1 A 91
1 A 87
1 A 86
2 B 100
2 B 94
2 B 93
2 B 90
2 B 89
2 B 89
2 B 87
2 B 86
3 C 100
3 C 98
3 C 98
3 C 97
3 C 92
3 C 91
3 C 90
The query I used to get this is something like this:
create or replace view xyz as
select *
from abc
where id in
(select id
from data)
order by id, mark desc, id;
And based on unique ids I want the top 5 rows:
ID | NAME |......Other Data... | Marks
1 A 100
1 A 100
1 A 99
1 A 95
1 A 94
2 B 100
2 B 94
2 B 93
2 B 90
2 B 89
3 C 100
3 C 98
3 C 98
3 C 97
3 C 92
I tried referring to this:
MySQL: Select top 5 rows based on ID and find Subtotal
But I wasn't able to do it. Could you please help?
You can use a windowed rank(), partitioned by each student name, and ordered by marks descending, to find the top 5 marks for each Student:
WITH cteRankedMarks AS
(
SELECT "ID", "NAME", "Marks",
rank() OVER (PARTITION BY "NAME"
ORDER BY "Marks" DESC) AS rank
FROM MyTable
)
SELECT "ID", "NAME", "Marks"
FROM cteRankedMarks
WHERE rank <= 5
ORDER BY "NAME", "Marks" DESC;
SqlFiddle here
Notes
If two or more marks have the same value vying for 5th place, then , then rank will return all such marks. If you don't want ties, then use row_number() instead of rank(). More about these here
Obviously, if a student doesn't have 5 marks, then fewer rows will be returned.

How to add a calculated column of certain rows in SQL

I want to add a calculated column (persisted) that is the total rows for the same group of categories such as sales order below. How would you do this in SQL Server?
SalesOrder Amount Total(calculated)
100 10 25
100 15 25
101 20 45
101 25 45
102 30 65
102 35 65
The best mechanism to use for storing pre-calculated aggregates that are automatically maintained would be an indexed view, it is not possible via a persisted computed column (you could use a scalar UDF in a computed column to calculate the result but this can't be persisted and such computed columns are generally bad for performance both as they force RBAR evaluation and as they block parallelism).
CREATE VIEW dbo.AggregatedSales
WITH SCHEMABINDING
AS
SELECT SalesOrder,
SUM(Amount) AS Total
FROM dbo.YourTable
GROUP BY SalesOrder
GO
CREATE UNIQUE CLUSTERED INDEX UIX ON dbo.AggregatedSales(SalesOrder)
Then the aggregates will be pre calculated and stored in the view. Your queries will need to join on the view. You may need to use the NOEXPAND hint to be sure that the pre calculated aggregates are in fact used and they aren't recalculated at runtime.
For SQL server 2012
CREATE TABLE #t (saleOrder int , amount int)
INSERT INTO #t VALUES
(100,10)
,(100,15)
,(101,20)
,(101,25)
,(102,30)
,(102,35)
SELECT *
,SUM(amount) OVER (PARTITION BY saleorder) as [total]
FROM #t
Result :
saleOrder | amount | total
==========================
100 | 10 | 25
100 | 15 | 25
101 | 20 | 45
101 | 25 | 45
102 | 30 | 65
102 | 35 | 65

Query is very slow

I have tables
table1
epid etid id EValue reqdate
----------- ----------- ----------- ------------ ----------
15 1 1 498925307069 2012-01-01
185 1 2 A5973FC43CE3 2012-04-04
186 1 2 44C6A4B776A2 2012-04-05
205 1 2 7A0ED3F1DA13 2012-09-19
206 1 2 77771D65F9C4 2012-09-19
207 1 2 AD74A4AA41BD 2012-09-19
208 1 2 9595ABE5A0C8 2012-09-19
209 1 2 7611D2FB395B 2012-09-19
210 1 2 04A510D6067A 2012-09-19
211 1 2 24D43EC268F8 2012-09-19
table2
PEId Id EPId
----------- ----------- -----------
43 9 15
44 10 15
45 11 15
46 12 15
47 13 15
48 14 15
49 15 15
50 16 15
51 17 15
52 18 15
table3
PLId PEId Id ToPayId
----------- ----------- ----------- -----------
71 43 9 1
72 43 9 2
73 44 10 1
74 44 10 2
75 45 11 1
76 45 11 2
77 46 12 1
78 46 12 2
79 47 13 1
80 47 13 2
I want to get one id whose count is less than 8 in table 3 and order by peid in table 2,
I have written query
SELECT Top 1 ToPayId FROM
(
SELECT Count(pl.ToPayId) C, pl.ToPayId
FROM table3 pl
INNER JOIN table2 pe ON pl.peid = pe.peid
INNER JOIN table1 e ON pe.epid = e.epid
WHERE e.EtId=1 GROUP BY pl.ToPayId
) As T
INNER JOIN table2 p ON T.ToPayId= p.Id
WHERE C < 8 ORDER BY p.PEId ASC
This query executes more than 1000 times in stored procedure depends on the entries in user-defined-table-type using while condition.
But it is very slow as we have millions of entries in each table.
Can anyone suggest better query regarding above?
maybe try with the having clause to get rid of the from select
select table2.id as due
from table3 inner join table2 on table2.PEId=table3.PEId...
group by ...
having count(due) <8
order by ...
-> you have a redundant Id column in table3 : seems pretty useless as the couple PEId and Id appears unique so remove it and reduce the size of table 3 by 25% hence improving performance of db
Will.. since you did not provide enough sample data and I am not sure what exactly your business logic is. So that I can just modify the code in blind.
SELECT ToPayId
FROM (
SELECT TOP 1 Count(pl.ToPayId) C, pl.ToPayId, pe.PEId
FROM table3 as pl
INNER JOIN table2 as pe ON pl.peid = pe.peid AND pl.ToPayId = pe.Id
INNER JOIN table1 e ON pe.epid = e.epid
WHERE e.EtId=1
GROUP BY pl.ToPayId, pe.PEId
HAVING Count(pl.ToPayId) < 8
ORDER BY pe.PEId ASC
) AS T

Resources