two sql query mix for one - sql

I want to combine two pieces of code into one, but I'm getting an error:
Part 1
SELECT idstd,namestd, idmajor,
c1, c2, c3, c4, c5, c6,
c7, c8, c9, c10,c11,c12,
c13,c14,c15
FROM
(SELECT status, idstd,namestd, idmajor,
'C' + cast(row_number()
OVER (partition BY idstd, idmajor
ORDER BY (SELECT 1)) AS varchar(10)) col
FROM tbcheked) src
PIVOT (MAX(status) FOR col IN (C1, C2, C3, C4, C5,
C6, C7, C8, C9, C10,
c11,c12,c13,c14,c15)) piv
This code is for checking if the column status has values of present, absent or leave.
Example:
id | c1 | c2 | c3 | c4 | c5 |
1 present absent present leave present
I have the second piece of code for status count:
SELECT idstd,
namemajor,
SUM(CASE WHEN status = 'present'
THEN 1
ELSE 0
END) AS present,
SUM(CASE WHEN status = 'absent'
THEN 1
ELSE 0
END) AS absent,
SUM(CASE WHEN status = 'leave'
THEN 1
ELSE 0
END) AS leave,
FROM tbcheked GROUP BY idstd, namemajor
ORDER BY idstd
Output:
id | present | absent | leave |
1 3 1 1
Now, I want to join both queries:
id | c1 | c2 | c3 | c4 | c5 | present | absent | leave |
1 present absent present leave present 3 1 1

Use join for conbining the output of both the queries.
select a.*, b.*
from (query 1)a join (query 2)b on a.id=b.id;

Treat each part as a sub-query and join them:
select
<whatever>
from
(
SELECT idstd,namestd, idmajor,
c1, c2, c3, c4, c5, c6,
c7, c8, c9, c10,c11,c12,
c13,c14,c15
FROM
(SELECT status, idstd,namestd, idmajor,
'C' + cast(row_number()
OVER (partition BY idstd, idmajor
ORDER BY (SELECT 1)) AS varchar(10)) col
FROM tbcheked) src
PIVOT (MAX(status) FOR col IN (C1, C2, C3, C4, C5,
C6, C7, C8, C9, C10,
c11,c12,c13,c14,c15)) piv
) as PivotedBit
INNER JOIN -- or OUTER, depending on your requirement
(
SELECT idstd,
namemajor,
SUM(CASE WHEN status = 'present'
THEN 1
ELSE 0
END) AS present,
SUM(CASE WHEN status = 'absent'
THEN 1
ELSE 0
END) AS absent,
SUM(CASE WHEN status = 'leave'
THEN 1
ELSE 0
END) AS leave,
FROM tbcheked GROUP BY idstd, namemajor
--ORDER BY idstd -- cannot have this in a sub-query
) as SummingBit
on SummingBit.idstd = PivotedBit.idstd
-- and any other common keys
ORDER BY idstd
It'll do two complete scans of tbcheked, so it won't be fast.
I have a hunch that adding dummy columns to the inner select of the PIVOT query using the CASE statements from the summing query, then adding SUM() to the PIVOT clause would be better. I haven't thought this through fully, however.

Related

Sql group by sum of each group

I have a table like this:
C1 C2 C3 C4 C5 C6
INTERESES 40530 5 050405011232011 2013 5
PRINCIPAL 40529 5 050405011232011 2016 3
PRINCIPAL 40530 5 050405011232011 2013 4
And i need to group this rows by C1, C3 and C4 and return in the cases of lane 2 and 3 the C2 column with the max C5. I mean in this case this should return:
C1 C2 C3 C4 C5
INTERESES 40530 5 050405011232011 5
PRINCIPAL 40529 5 050405011232011 7
The second row should have 40529 in the column C2 cause it have the biggest value in the C5 column.
The C5 column should have the sum of the C6 of the previous table.
How can i do this? Thanks and sorry for my english
Instead of aggregation, one method uses window functions:
select c1, c2, c3, c4, sum_c5
from (select t.*,
sum(c5) over (partition by c1, c3, c4) as sum_c5,
row_number() over (partition by c1, c3, c4 order by c5 desc) as seqnum
from t
) t
where seqnum = 1;
Oracle also has keep syntax with allows you to get the "first" value in an aggregation:
select c1,
max(c2) keep (dense_rank first order by c5 desc) as c2,
c3, c4,
sum(c5)
from t
group by c1, c3, c4;
You can do it with NOT EXISTS:
select t.c1, t.c2, t.c3, t.c4
from tablename t
where not exists (
select 1 from tablename
where c1 = t.c1 and c2 = t.c2 and c3 = t.c3 and c5 > t.c5
)

How to reference result from previous 2 column like Excel formular

SELECT
Answer_Code AS C0,
Text AS C1,
Price AS C2,
sum(case when Response like '%PAID%' then 1 else 0 end) AS C3,
C2 * C3 AS 'Total' --Invalid column name 'C2'.--
FROM TableA
How to reference C2 and C3, then do multiplication in that position ?
Any techniques ?
You can use inner-select:
SELECT *, C2 * C3 As Total
FROM (
SELECT
Answer_Code AS C0,
Text AS C1,
Price AS C2,
sum(case when Response like '%PAID%' then 1 else 0 end) AS C3,
FROM TableA) DT;
or use a CTE like this:
;WITH t AS (
SELECT
Answer_Code AS C0,
Text AS C1,
Price AS C2,
sum(case when Response like '%PAID%' then 1 else 0 end) AS C3,
FROM TableA)
SELECT *, C2 * C3 As Total
FROM t;
You can use with clause or a sub query.
;with tmp_tbl as (
SELECT
Answer_Code AS C0,
Text AS C1,
Price AS C2,
sum(case when Response like '%PAID%' then 1 else 0 end) AS C3
--C2 * C3 AS 'Total' --Invalid column name 'C2'.--
FROM TableA
)
select
C0,
C1,
C2,
C3,
C2 * C3 AS 'Total'
from tmp_tbl;

How to select entry with greater value in postgresql

I have two or more values like:
c1|c2 |c3 |c4
--+---+---+---
1 | Z | B | 29
2 | Z | B | 19
and I want to have the entry with the larger c4 value:
1 | Z | B | 29
I tried to query the max value from c4, after a group by of c2 and c3, but this doesn't work.
Postgres specific solution:
select distinct on (c2,c3) c1, c2, c3, c4
from the_table
order by c2,c3,c4 desc
ANSI SQL solution:
select c1,c2,c3,c4
from (
select c1,c2,c3,c4,
row_number() over (partition by c2,c3 order by c4 desc) as rn
from the_table
) t
where rn = 1;
You can order results in descending order by c4 and output only one row (see LIMIT clause):
SELECT *
FROM table_name
ORDER BY c4 DESC
LIMIT 1

SQL Server : unsure how to retrieve selected records

In this example, can I retrieve only rows BB, DD, and FF using T-SQL syntax and a single select statement?
C1 | C2 | C3 | C4
-----------------
AA | KK | 11 | 99
BB | KK | 11 | 99
CC | KK | 22 | 99
DD | KK | 22 | 99
EE | KK | 33 | 99
FF | KK | 33 | 99
Ok, so this is what I ended up with to solve my problem: SELECT distinct [C4], [C1], [C2], [C3] FROM [Table] where [C4] = 'MyValue' order by [C3] desc.
Give this a shot:
SELECT C1, C2, C3, C4 FROM mytable WHERE C1 IN ('BB', 'DD', 'FF')
If you want to unique the C3 column the query should be:
SELECT MAX(C1), C2, C3, C4 FROM mytable GROUP BY C2, C3, C4
Try this
SELECT t.C1, t.C2, t.C3, t.C4 FROM
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY C3 ORDER BY C1 DESC) AS seqnum
FROM MyTable
) t
WHERE seqnum = 1
This would work for your particular example:
SELECT
C1 = MAX(C1),
C2,
C3,
C4
FROM atable
GROUP BY
C2,
C3,
C4
;
If picking the right value from C1 should follow a more complex logic than just getting the MAX() one, you'll probably need to use #bvr's suggestion (tuning the ORDER BY clause properly).

T-SQL for changing data from one table and insert into another table

My base table is like:
ColumnA|ColumnB
---------------
A | C1
A | C2
A | C3
B | C1
B | C3
C | C4
I want to read records from the base table and write it into the below table:
ColumnA | C1 | C2 | C3 | C4
----------------------------
A | Y | Y | Y | N
B | Y | N | Y | N
C | N | N | N | Y
I don't want to use a cursor, but I don't know if that's possible or not.
Thanks
Have a look at the PIVOT command. From there you can do a INSERT INTO ... SELECT ...
SELECT ColumnA, [C1], [C2], [C3], [C4]
FROM (SELECT * FROM table) t
PIVOT
(
Count(ColumnB)
FOR ColumnB IN ([C1], [C2], [C3], [C4])
) As Pvt
One (usually fast) way would be group by:
insert NewTable (ColumnA, C1, C2, C3, C4)
select ColumnA
, IsNull(max(case when ColumnB = 'C1' then 'Y' end), 'N')
, IsNull(max(case when ColumnB = 'C2' then 'Y' end), 'N')
, IsNull(max(case when ColumnB = 'C3' then 'Y' end), 'N')
, IsNull(max(case when ColumnB = 'C4' then 'Y' end), 'N')
from OldTable
group by
ColumnA
Another way is subqueries, like:
insert NewTable (ColumnA, C1, C2, C3, C4)
select src.ColumnA
, case when exists (select * from OldTable ot
where ot.ColumnA = src.ColumnA and ot.ColumnB = 'C1')
then 'Y' else 'N' end
, case when exists (select * from OldTable ot
where ot.ColumnA = src.ColumnA and ot.ColumnB = 'C2')
then 'Y' else 'N' end
, case when exists (select * from OldTable ot
where ot.ColumnA = src.ColumnA and ot.ColumnB = 'C3')
then 'Y' else 'N' end
, case when exists (select * from OldTable ot
where ot.ColumnA = src.ColumnA and ot.ColumnB = 'C4')
then 'Y' else 'N' end
from (
select distinct ColumnA
from OldTable
) src
Or, adapted from Chris Diver's answer, with pivot:
select ColumnA
, case when C1 > 0 then 'Y' else 'N' end C1
, case when C2 > 0 then 'Y' else 'N' end C2
, case when C3 > 0 then 'Y' else 'N' end C3
, case when C4 > 0 then 'Y' else 'N' end C4
from OldTable src
pivot (
count(ColumnB)
for ColumnB IN ([C1], [C2], [C3], [C4])
) pvt
assuming you can SELECT the information you like, then you can write the insert as the result of that selection.