Horizontal To Vertical Sql Server - sql

I'm stuck with a SQL query (SQL Server) that involves converting horizontal rows to vertical rows
Below is my Query that I am trying
SELECT P AS Amount_Rs
FROM (
Select (F1.D32-F1.D20) As Profit_For_The_Period ,F3.D2 as Current_Libilities,F5.D20 As Capital_Acount,
--M1.Name As Name,
F2.D20 AS Loan_Liabilities,F4.d1 As Opening_Diff --F2.D68 As Loan,
from Folio1 As F1
--inner Join Master1 As m1 on m1.Code like '101' or m1.Code Like '102' or m1.Code Like '106' or m1.Code Like '109' or m1.Code lIke '103'
--And m1.Code=102 And m1.Code=101)
inner Join Folio1 As F2 On (F2.MasterCode=F2.MasterCode)
inner Join Folio1 As F3 On (F3.MasterCode=F3.MasterCode)
inner Join Folio1 As F4 On (F4.MasterCode=F4.MasterCode)
inner Join Folio1 As F5 On (F5.MasterCode=F5.MasterCode)
Where F1.MasterCode=109
and F2.MasterCode =106
and F3.MasterCode=103
and F4.MasterCode=102
And F5.MasterCode=101
) p UNPIVOT
( p FOR value IN
( Profit_For_The_Period,Capital_Acount, Current_Libilities, Loan_Liabilities, Opening_Diff )
) AS unvpt
Current Output:
1 12392
2 0
3 0
4 4000
5 -200
Desired Output:
1 Capital Account 12392
2 Current Assets 0
3 Current Liabilities 0
4 Loans (Liability) 4000
5 Revenue Accounts -200
Thanks !!!

I think you are looking for a pivot. Use the CASE statement with a SUM or any aggregate function in the SELECT part and a group by in the where clause, that's how I use to put rows into columns in a query when I have to in MySQL. I don't know SQL Server but I think you can do quite the same.
your conditions below
F1.MasterCode=109
and F2.MasterCode =106
and F3.MasterCode=103
and F4.MasterCode=102
And F5.MasterCode=101
shouldn't be in the the where clause but with the case in the select part
example :
select whatever,
case when F2.MasterCode =106 then sum(column_name)
end case as column_alias, (other columns) from ...
hope this could help

Related

Left outer join column name ambiguously defined

I have a table task
select
sts_id,
count(*) mycount
from
task
where
sts_id in (1, 8, 39)
group by sts_id;
output :
sts_id count
1 1
8 1
39 1
I have one more temp table with one column sts_id
which looks like this
sts_id
1
8
39
40
41.
I am trying for a left join for both the tables
select
in_list.sts_id,
count(*) mycount
from
task
left outer join
in_list
on task.sts_id = in_list.sts_id
group by sts_id;
to get ab o/p like
1 1
8 1
39 1
40 0
41 0..
I am getting an error of column ambiguously defined.
You are using left join the wrong way (on the left it must be the table with all the rows you want to show).
Count (task.sts_id) to get 0 on rows without ocurrences on that table
select
in_list.sts_id,
count(task.sts_id) mycount
from
in_list
left outer join
task
on in_list.sts_id = task.sts_id
AND task.sts_id in (1, 8, 39) -- Thanks Matt.
group by in_list.sts_id;
You are missing the table alias in the GROUP BY clause.
However, your needed result says that you need to change your join logic: the starting table should be in_list, while task should be in left outer join:
select ...
from in_list
left outer join task
select
in_list.sts_id,
coalesce(count(task.sts_ID),0) mycount --changed this line
from
task
right outer join --changed this line
in_list
on task.sts_id = in_list.sts_id
group by in_list.sts_id; -- changed this line
Reasons:
as in_list contains more data than task, we needed to either change the table order or make it a right join
Count would count all records and not return resutls you want the count from task
need to coalesce the results otherwise null count will return null not 0.
I got my answer with this query
select t2.sts_id, count(t.sts_id)
from task t, in_list t2
where t2.sts_id = t.sts_id(+)
group by t2.sts_id
Thanks,

T-SQL cursor or if or case when

I have this table:
Table_NAME_A:
quotid itration QStatus
--------------------------------
5329 1 Assigned
5329 2 Inreview
5329 3 sold
4329 1 sold
4329 2 sold
3214 1 assigned
3214 2 Inreview
Result output should look like this:
quotid itration QStatus
------------------------------
5329 3 sold
4329 2 sold
3214 2 Inreview
T-SQL query, so basically I want the data within "sold" status if not there then "inreview" if not there then "assigned" and also at the same time if "sold" or "inreview" or "assigned" has multiple iteration then i want the highest "iteration".
Please help me, thanks in advance :)
This is a prioritization query. One way to do this is with successive comparisons in a union all:
select a.*
from table_a a
where quote_status = 'sold'
union all
select a.*
from table_a a
where quote_status = 'Inreview' and
not exists (select 1 from table_a a2 where a2.quoteid = a.quoteid and a2.quotestatus = 'sold')
union all
select a.*
from table_a a
where quote_status = 'assigned' and
not exists (select 1
from table_a a2
where a2.quoteid = a.quoteid and a2.quotestatus in ('sold', 'Inreview')
);
For performance on a larger set of data, you would want an index on table_a(quoteid, quotestatus).
You want neither cursors nor if/then for this. Instead, you'll use a series of self-joins to get these results. I'll also use a CTE to simplify getting the max iteration at each step:
with StatusIterations As
(
SELECT quotID, MAX(itration) Iteration, QStatus
FROM table_NAME_A
GROUP BY quotID, QStats
)
select q.quotID, coalesce(sold.Iteration,rev.Iteration,asngd.Iteration) Iteration,
coalesce(sold.QStatus, rev.QStatus, asngd.QStatus) QStatus
from
--initial pass for list of quotes, to ensure every quote is included in the results
(select distinct quotID from table_NAME_A) q
--one additional pass for each possible status
left join StatusIterations sold on sold.quotID = q.quotID and sold.QStatus = 'sold'
left join StatusIterations rev on rev.quotID = q.quotID and rev.QStatus = 'Inreview'
left join StatusIterations asngd on asngd.quotID = q.quotID and asngd.QStatus = 'assigned'
If you have a table that equates a status with a numeric value, you can further improve on this:
Table: Status
QStatus Sequence
'Sold' 3
'Inreview' 2
'Assigned' 1
And the code becomes:
select t.quotID, MAX(t.itration) itration, t.QStatus
from
(
select t.quotID, MAX(s.Sequence) As Sequence
from table_NAME_A t
inner join Status s on s.QStatus = t.QStatus
group by t.quotID
) seq
inner join Status s on s.Sequence = seq.Sequence
inner join table_NAME_A t on t.quotID = seq.quotID and t.QStatus = s.QStatus
group by t.quoteID, t.QStatus
The above may look like complicated at first, but it can be faster and it will scale easily beyond three statuses without changing the code.

How to use multiple count and where condition sql server 2008?

I have this two query
1.
select CL_Clients.cl_id,CL_Clients].cl_name,COUNT(*) AS number_of_orders
from CL_Clients,CLOI_ClientOrderItems
where CL_Clients.cl_id=CLOI_ClientOrderItems.cl_id
group by CL_Clients.cl_name,CL_Clients.cl_id
2.
select CL_Clients.cl_id,count(cloi_current_status) as dis
from CLOI_ClientOrderItems,CL_Clients
where cloi_current_status]='12'
and CL_Clients.cl_id=CLOI_ClientOrderItems.cl_id
group by CL_Clients.cl_name,CL_Clients.cl_id,CLOI_ClientOrderItems.cloi_current_status
i have this column i need to put count function and where condition
[cloi_current_status]
166
30
30
30
150
150
150
150
150
150
150
Quite simple, you just encapsulate the queries and give their result sets an alias and then do a JOIN between their aliases on the column that is common. (In the query below I assume you'll be joining by client id)
SELECT *
FROM (
SELECT CL_Clients.cl_id,
CL_Clients].cl_name,
COUNT(*) AS number_of_orders
FROM CL_Clients,
CLOI_ClientOrderItems
WHERE CL_Clients.cl_id = CLOI_ClientOrderItems.cl_id
GROUP BY CL_Clients.cl_name,
CL_Clients.cl_id
) A
INNER JOIN (
SELECT CL_Clients.cl_id,
count(cloi_current_status) AS dis
FROM CLOI_ClientOrderItems,
CL_Clients
WHERE cloi_current_status] = '12'
AND CL_Clients.cl_id = CLOI_ClientOrderItems.cl_id
GROUP BY CL_Clients.cl_name,
CL_Clients.cl_id,
CLOI_ClientOrderItems.cloi_current_status
) B
ON A.cl_id = B.cl_id
WHERE ...
GROUP BY ...
This will be treated as a separate result set, so you can also filter results with a WHERE or just a GROUP BY, just like in a normal SELECT.
UPDATE:
To answer the question in your comments, when you join two tables that have a column with the same value and use
SELECT * FROM A INNER JOIN B the * will show all columns returned by the join, meaning all columns from A and all columns from B, this is why you have duplicate columns.
If you want to filter the columns returned you can specifiy which columns you want returned. So, in your case, the top SELECT * can be replaced with
SELECT A.cl_id, A.cl_name, A.number_of_orders, B.dis so, your query becomes:
SELECT A.cl_id, A.cl_name, A.number_of_orders, B.dis
FROM (
SELECT CL_Clients.cl_id,
CL_Clients].cl_name,
COUNT(*) AS number_of_orders
FROM CL_Clients,
CLOI_ClientOrderItems
WHERE CL_Clients.cl_id = CLOI_ClientOrderItems.cl_id
GROUP BY CL_Clients.cl_name,
CL_Clients.cl_id
) A
INNER JOIN (
SELECT CL_Clients.cl_id,
count(cloi_current_status) AS dis
FROM CLOI_ClientOrderItems,
CL_Clients
WHERE cloi_current_status] = '12'
AND CL_Clients.cl_id = CLOI_ClientOrderItems.cl_id
GROUP BY CL_Clients.cl_name,
CL_Clients.cl_id,
CLOI_ClientOrderItems.cloi_current_status
) B
ON A.cl_id = B.cl_id
UPDATE #2:
For your last question, you need to GROUP BY at the end of the big query and use a HAVING condtion, like this:
GROUP BY A.cl_id, A.cl_name, A.number_of_orders, B.dis
HAVING COUNT(cloi_current_status) > 100
All depends on what data you are trying to get, but you can go about it like this.
SELECT Column_x, Column_y, etc..
FROM ClL_Clients a
JOIN (select CL_Clients.cl_id,CL_Clients].cl_name,COUNT(*) AS number_of_orders
from CL_Clients,CLOI_ClientOrderItems
where CL_Clients.cl_id=CLOI_ClientOrderItems.cl_id
group by CL_Clients.cl_name,CL_Clients.cl_id) b
on a.cl_id = b.cl_id
JOIN (select CL_Clients.cl_id,count(cloi_current_status) as dis
from CLOI_ClientOrderItems,CL_Clients
where cloi_current_status]='12'
and CL_Clients.cl_id=CLOI_ClientOrderItems.cl_id
group by CL_Clients.cl_name,CL_Clients.cl_id,CLOI_ClientOrderItems.cloi_current_status) c
on a.cl_id = c.cl_id
Group by BLAH BLAH
Hope this gets you in the right direction.

How to combine columns in sql based on another field

I have a table in SQL Server 2008 R2 like this:
Acc_id Bench-1 Bench-2
-------------------------------
1 xx
1 vv
2 pp
2 ii
3 kk
4 ll
Now, I want to combine this table on the basis of Acc_id column and get something like:
Acc_id Bench-1 Bench-2
---------------------------------
1 xx vv
2 pp ii
3 kk
4 ll
So, could someone please help me out.
SELECT ISNULL(b1.Acc_id,b2.Acc_id) as Acc_id,
b1.data,
b2.data
FROM Bench-1 AS b1 FULL OUTER JOIN
Bench-2 AS b2 ON b2.Acc_id = b1.Acc_id
Check Below query
SELECT DISTINCT a.acc_id,
b.bench_1,
c.bench_2
FROM table1 a
LEFT OUTER JOIN (SELECT acc_id,
bench_1
FROM table1
WHERE Isnull(bench_1, '') <> '') b
ON a.acc_id = b.acc_id
LEFT OUTER JOIN (SELECT acc_id,
bench_2
FROM table1
WHERE Isnull(bench_2, '') <> '') c
ON a.acc_id = c.acc_id
I would do this like:
select
Acc_id,
max([Bench-1)] as [Bench-1],
max(([Bench-2]) as [Bench-2]
from
myTable
group by
Acc_id
This assumes Acc_id won't have multiple rows with data in the same columns
If that is the case then your knowledge of the use of the results will come into play. I often will perform this more completely like
select
Acc_id,
min([Bench-1)] as [Bench-1Min],
max([Bench-1)] as [Bench-1Max],
Count([Bench-1)] as [Bench-1Count],
min([Bench-2)] as [Bench-2Min],
max([Bench-2)] as [Bench-2Max],
Count([Bench-2)] as [Bench-2Count],
from
myTable
group by
Acc_id
All this depends on the actual complexity of the real data and what you want to do with the results. If it IS actually as simple as you example the multi-join solution may work for you, but I often find that in more complex summarizations the group by solution give me results and performance I need.

How to remove duplicating rows from union statement

OK - I have looked and looked and found a lot of examples but nothing quite meeting my need. Maybe I used the wrong words to search with, but I could use your help. I will provide as much detail as I can.
I need to produce a report that merges fields from two tables, or rather a view and a table, into one table for a report. Here is the statement I am using:
SELECT A.ConfInt, A.Conference,
NULL as Ordered,
NULL as Approved,
NULL as PickedUp,
SUM(dbo.Case_Visit_Payments.Qty) AS Qty
FROM dbo.Conferences as A INNER JOIN
dbo.Case_Table ON A.ConfInt = dbo.Case_Table.Conference_ID INNER JOIN
dbo.Case_Visit_Payments ON dbo.Case_Table.Case_ID = dbo.Case_Visit_Payments.Case_ID
WHERE (dbo.Case_Visit_Payments.Item_ID = 15 AND A.ProjectCool = 1)
GROUP BY A.Conference, A.ConfInt
UNION
SELECT B.ConfInt,
B.Conference,
SUM(dbo.Cool_Fan_Order.NumberOfFansRequested) AS Ordered,
SUM(dbo.Cool_Fan_Order.Qty_Fans_Approved) AS Approved,
SUM(dbo.Cool_Fan_Order.Qty_Fans_PickedUp) AS PickedUp,
NULL AS Qty
FROM dbo.Conferences as B LEFT OUTER JOIN
dbo.Cool_Fan_Order ON B.ConfInt = dbo.Cool_Fan_Order.Conference_ID
where B.ProjectCool = 1
GROUP BY B.Conference, B.ConfInt
And here are the results:
4 Our Lady NULL NULL NULL 11
4 Our Lady 40 40 40 NULL
7 Holy Rosary 20 20 20 NULL
11 Little Flower NULL NULL NULL 21
11 Little Flower 5 5 20 NULL
19 Perpetual Help NULL NULL NULL 2
19 Perpetual Help 20 20 20 NULL
What I would strongly prefer is to not have the duplicating rows, such as:
4 Our Lady 40 40 40 11
7 Holy Rosary 20 20 20 NULL
11 Little Flower 5 5 20 21
19 Perpetual Help 20 20 20 2
I hope this question was clear enough. Any Suggestions would be greatly appreciated. And I do mark as answered. :)
Gregory
you could use your actual query as a subQuery, use an aggregate function (MAX OR SUM) on your non-duplicated values and group by the non aggregated columns
SELECT ConfInt, Conference, MAX(Ordered), MAX(Approved), MAX(PickedUp), MAX(Qty)
FROM (<your actualQuery>)
GROUP BY ConfInt, Conference.
The quick answer is to wrap your query inside another one,
SELECT ConfInt
, Conference
, SUM(Ordered) AS Ordered
, SUM(Approved) As Approved
, SUM(PickedUp) AS PickedUp
, SUM(Qty) AS Qty
FROM (
<your UNION query here>
)
GROUP BY ConfInt, Conference
This is not the only way to achieve the result set, but its the quickest fix to meet the specified requirements.
As an alternative, I believe these queries will return equivalent results:
We could use a correlated subquery in the SELECT list to get Qty:
;WITH q AS
( SELECT B.ConfInt
, B.Conference
, SUM(o.NumberOfFansRequested) AS Ordered
, SUM(o.Qty_Fans_Approved) AS Approved
, SUM(o.Qty_Fans_PickedUp) AS PickedUp
FROM dbo.Conferences as B
LEFT
JOIN dbo.Cool_Fan_Order o ON o.Conference_ID = B.ConfInt
WHERE B.ProjectCool = 1
GROUP BY B.ConfInt, B.Conference
)
SELECT q.ConfInt
, q.Conference
, q.Ordered
, q.Approved
, q.PickedUp
, ( SELECT SUM(v.Qty)
FROM dbo.Case_Table t
JOIN dbo.Case_Visit_Payments v ON v.Case_ID = t.Case_ID
WHERE t.Conference_ID = q.ConfInt
AND v.Item_ID = 15
) AS Qty
FROM q
ORDER BY q.ConfInt, q.Conference
Or, we could use LEFT JOIN operation on the two queries, rather than UNION. (We know that the query referencing Cool_Fan_Order can be the LEFT side of the outer join, because we know that it returns at least as many rows as the other query. (Basically, we know that the other query can't return values of ConfInt and Conference that aren't in the Cool_Fan_Order query.)
;WITH p AS
( SELECT A.ConfInt
, A.Conference
, SUM(v.Qty) AS Qty
FROM dbo.Conferences as A
JOIN dbo.Case_Table t ON t.Conference_ID = A.ConfInt
JOIN dbo.Case_Visit_Payments v ON v.Case_ID = t.Case_ID
WHERE A.ProjectCool = 1
AND v.Item_ID = 15
GROUP BY A.ConfInt, A.Conference
)
, q AS
( SELECT B.ConfInt
, B.Conference
, SUM(o.NumberOfFansRequested) AS Ordered
, SUM(o.Qty_Fans_Approved) AS Approved
, SUM(o.Qty_Fans_PickedUp) AS PickedUp
FROM dbo.Conferences as B
LEFT
JOIN dbo.Cool_Fan_Order o ON B.ConfInt = o.Conference_ID
WHERE B.ProjectCool = 1
GROUP BY B.ConfInt, B.Conference
)
SELECT q.ConfInt
, q.Conference
, q.Ordered
, q.Approved
, q.PickedUp
, p.Qty
FROM q
LEFT
JOIN p ON p.ConfInt = q.ConfInt AND p.Conference = q.Conference
ORDER BY q.ConfInt, q.Conference
The choice between those three (they all return an equivalent resultset under all conditons), boils down to readability and maintainability, and performance. On large enough rowsets, there may be some observable performance differences between the three statements.
I'd just put the join to Cool_Fan_Order in the first select and remove the union.
Does this return the same results?
select
A.ConfInt,
A.Conference,
sum(dbo.Cool_Fan_Order.NumberOfFansRequested) as Ordered,
sum(dbo.Cool_Fan_Order.Qty_Fans_Approved) as Approved,
sum(dbo.Cool_Fan_Order.Qty_Fans_PickedUp) as PickedUp,
sum(sub.Qty) as Qty
from
dbo.Conferences as A
left outer join
(
select
c.ConfInt,
cvp.Qty
from dbo.Conferences c
inner join dbo.Case_Table ct
on a.confInt=ct.Conference_ID
inner join dbo.Case_Visit_Payments cvp
on ct.Case_ID=cvp.Case_ID
where cvp.Item_ID=15
) sub
on a.ConfInt=sub.ConfInt
left outer join dbo.Cool_Fan_Order
on A.ConfInt = dbo.Cool_Fan_Order.Conference_ID
where
(
A.ProjectCool = 1
)
group by
A.Conference,
A.ConfInt