Compare field in single row to entire column - reporting-services

I have a column of dates, and I would like to have a second column that tallies the total amount of times a date in the first column shows up over the whole column. I am trying to use Count(IIf(...)), but I don't know how to specify that SSRS use the current row as the standard, and then check the whole column for the count.
Dates Records
9/14/18 2
9/14/18 2
9/15/18 1
9/16/18 3
9/16/18 3
9/16/18 3

Assuming you are not using a very old version of SQL Server then you could just do something simple like
SELECT
*
, COUNT(*) OVER(PARTITION BY PartTran_TranDate) AS DateCount
FROM myTable

Perhaps this will help. I changed it up a little bit for simplicity:
DECLARE #Table TABLE (DateCol DATE)
INSERT #Table
VALUES ('9/14/18'),
('9/14/18'),
('9/15/18'),
('9/16/18'),
('9/16/18'),
('9/16/18')
SELECT t.DateCol, r.rn
FROM #Table t
OUTER APPLY (SELECT COUNT(DateCol) rn
FROM #Table t2
WHERE t2.DateCol = t.DateCol
GROUP BY t2.DateCol) r

Related

Find next or previous ID when query contains multiple cases

I am looking for the most efficient way to find the next or previous ID of the following query:
SELECT *
FROM transactions
ORDER
BY CASE order_status
WHEN 'order_accepted' THEN 1
WHEN 'processing_order' THEN 2
WHEN 'order_send_mailer' THEN 3
WHEN 'order_send' THEN 4
WHEN 'order_received' THEN 5
WHEN 'order_refunded' THEN 6
ELSE 7 END
, id DESC limit 1;
I tried adding a where id > '$id' or where id < '$id' claus to the query but it didn't give me te next or previous ID I was looking for.
For those that need some explanation of what I am trying to do: It's to go to the next or previous order by case with a forward of backward button.
What it currently looks like:
-id- -order_status-
9399 order_accepted
9398 processing_order
9363 processing_order
9403 order_send_mailer
9318 order_send
9346 order_received
9345 order_received
9050 order_refunded
The next ID for example of 9403 would be 9363 and previous ID would be 9318
Change your order_status into an enum column. This will save disk space and make sorting by order_status simpler and faster.
-- Add a new version of the column using an enum.
-- These strings are aliases for ordered numbers.
-- 'order_accepted' is 1, 'processing_order' is 2, etc.
alter table transactions add column enum_order_status enum(
'order_accepted',
'processing_order',
'order_send_mailer',
'order_send',
'order_received',
'order_refunded'
) not null;
-- Copy the status into the new enum column.
-- MySQL will translate the string into the number for you.
update transactions
set enum_order_status = order_status;
-- Drop the old column.
alter table transactions drop column order_status;
-- Rename the new enum column.
alter table transactions rename column enum_order_status to order_status;
-- Index it.
create index transactions_order_status on transactions(order_status);
-- Enjoy your vastly simplified and much faster query.
select *
from transactions
order by order_status, id desc
That's not actually necessary, but it makes everything much simpler.
With that out of the way, use the window functions lead and lag to refer to the previous and next rows in a query.
select
id, order_status,
lead(id) over w, lead(order_status) over w,
lag(id) over w, lag(order_status) over w
from transactions
window w as (order by order_status, id desc);
Note, window functions were added in MySQL 8. If you're using an older version I recommend upgrading ASAP; MySQL 8 has many big improvements. Otherwise you can simulate it with correlated subqueries and self-joins.
If you want the previous and next rows of a specific row, use the technique from this answer. We add row_numbers to the table in the desired order, and then fetch 9403 and its previous and next row by row number.
-- Add a row number to your table in the desired order.
with ordered_transactions as (
select
*, row_number() over w as rn
from transactions
window w as (order by order_status, id desc)
)
select *
from ordered_transactions
-- Find the row number for ID 9403, then add -1, 0, and 1.
-- If 9403 is row number 5 you'll fetch row numbers 4, 5, and 6.
where ot.rn in (
select rn+i
from ordered_transactions ot
-- All this is doing is making us three "rows" where i = -1, 0, and 1.
cross join (SELECT -1 AS i UNION ALL SELECT 0 UNION ALL SELECT 1) cj
where ot.id = 9403
);
Try it.

How to Display 1 Column sum in other Column

I have a table that has different columns display different values.
I need to add a new column that displays sum of 1 column in each row of other column.
This is what i need to display.
I have written following query but its only displaying 1 in each row of last column.
select inStation.name TapInStation , outStation.name TapOutStation,
count(trx.passengerCount) PassengerCount, sum(trx.amount) Fare,
(select sum(passengerCount) from transactions iTrx
where iTrx.ID = trx.ID) PassengerPercent
from transactions trx
inner join
station inStation on inStation.ID = trx.fromStation
inner join
station outStation on outStation.ID = trx.toStation
GROUP BY
TapInStation, TapOutStation
If you want the total, then remove the correlation clause. This may do what you want:
select inStation.name as TapInStation , outStation.name as TapOutStation,
count(trx.passengerCount) as PassengerCount,
sum(trx.amount) as Fare,
(select sum(passengerCount) from transactions iTrx) as PassengerPercent
I'm not sure why you would called the "total" something like PassengerPercent, but this should return the overall total.
I also suspect that you might want a sum() for the previous expression.

how to doing group with two cels in a single sql

Here is my brief snipt:
select * from tbl_test
What I want to do is:
1.
select g_size, sum(g_num)
from tbl_test
group by g_size
2.
select m_size, sum(m_num)
from tbl_test
group by m_size
Here is my question, how can I push all these stuffs into one single sql string?
Is it possible to do this?
If you want single row for eigher single g_size or m_size then you can't do in single sql, but if it is okay for you that there can be multiple row for 1st group by field then you can do-
For example if you have one more row g_size=5, g_num=1, m_size=2, m_num=1 and you use below query-
select g_size, sum(g_num),m_size, sum(m_num)
from mytable
group by g_size,by m_size;
then you will get 2 rows for g_size=5 as per below-
g_size= 5, sum(g_num)=5, m_size=1, sum(m_num)=30
and
g_size= 5, sum(g_num)=1, m_size=2, sum(m_num)=1
Further you can use with rollup function which will first provide sub-total (m_size wise) and then total (g_size wise) and at the end grand total (all m_size grand total).
Simply add the columns and the group by:
select g_size, sum(g_num),m_size, sum(m_num) from tbl_test group by g_size, m_size;

Calculated value in another column

I have a table that has 4 column that needs to be calculated to get the average value. I know how to get the average value.
What I don't know how to do is to get get that value to show on another column on another table. How do I do that?
Example:
Columns: ID Size1 Size2 Size3 Size4
Values: 1 92 82 63 83
I know how to get the average value from that, but I need to know how a column in another table can refer to that average value. I am using PHPMyAdmin
Has stated in the comments if you just need this as a query result a join will do.
Select t1.ID,t2.ID,(T1.Size1 + T1.Size2 + T1.Size3 + T1.Size4) / 4 as Avg
From t1 join t2 on t1.ID = t2.ID;
This assumes that T1 is table one (has sizes) and T2 is the second table in which you have the other values that you want to add average to.
Now lets assume you want an avg column in another table to be tied to rows in your T1 (sizes) table. To do this you can use a trigger.
CREATE TRIGGER AvgValues
ON T1
AFTER INSERT
AS
BEGIN
INSERT INTO T2(Avg)
SELECT (T1.Size1 + T1.Size2 + T1.Size3 + T1.Size4) / 4
FROM T1
WHERE T1.ID = T2.ID
END

How to find the next record after a specified one in SQL?

I'd like to use a single SQL query (in MySQL) to find the record which comes after one that I specify.
I.e., if the table has:
id, fruit
-- -----
1 apples
2 pears
3 oranges
I'd like to be able to do a query like:
SELECT * FROM table where previous_record has id=1 order by id;
(clearly that's not real SQL syntax, I'm just using pseudo-SQL to illustrate what I'm trying to achieve)
which would return:
2, pears
My current solution is just to fetch all the records, and look through them in PHP, but that's slower than I'd like. Is there a quicker way to do it?
I'd be happy with something that returned two rows -- i.e. the one with the specified value and the following row.
EDIT: Sorry, my question was badly worded. Unfortunately, my definition of "next" is not based on ID, but on alphabetical order of fruit name. Hence, my example above is wrong, and should return oranges, as it comes alphabetically next after apples. Is there a way to do the comparison on strings instead of ids?
After the question's edit and the simplification below, we can change it to
SELECT id FROM table WHERE fruit > 'apples' ORDER BY fruit LIMIT 1
SELECT * FROM table WHERE id > 1 ORDER BY id LIMIT 1
Even simpler
UPDATE:
SELECT * FROM table WHERE fruit > 'apples' ORDER BY fruit LIMIT 1
So simple, and no gymnastics required
Select * from Table
where id =
(Select Max(id) from Table
where id < #Id)
or, based on the string #fruitName = 'apples', or 'oranges' etc...
Select * from Table
where id =
(Select Max(id) from Table
where id < (Select id from Table
Where fruit = #fruitName))
I'm not familiar with the MySQL syntax, but with SQL Server you can do something with "top", for example:
SELECT TOP 1 * FROM table WHERE id > 1 ORDER BY id;
This assumes that the id field is unique. If it is not unique (say, a foreign key), you can do something similar and then join back against the same table.
Since I don't use MySQL, I am not sure of the syntax, but would imagine it to be similar.
Unless you specify a sort order, I don't believe the concepts of "previous" or "next" are available to you in SQL. You aren't guaranteed a particular order by the RDBMS by default. If you can sort by some column into ascending or descending order that's another matter.
This should work. The string 'apples' will need to be a parameter.
Fill in that parameter with a string, and this query will return the entire record for the first fruit after that item, in alphabetical order.
Unlike the LIMIT 1 approach, this should be platform-independent.
--STEP THREE: Get the full record w/the ID we found in step 2
select *
from
fruits fr
,(
--STEP TWO: Get the ID # of the name we found in step 1
select
min(vendor_id) min_id
from
fruits fr1
,(
--STEP ONE: Get the next name after "apples"
select min(name) next_name
from fruits frx
where frx.name > 'apples'
) minval
where fr1.name = minval.next_name
) x
where fr.vendor_id = x.min_id;
The equivalent to the LIMIT 1 approach in Oracle (just for reference) would be this:
select *
from
(
select *
from fruits frx
where frx.name > 'apples'
order by name
)
where rownum = 1
I don't know MySQL SQL but I still try
select n.id
from fruit n
, fruit p
where n.id = p.id + 1;
edit:
select n.id, n.fruitname
from fruits n
, fruits p
where n.id = p.id + 1;
edit two:
Jason Lepack has said that that doesn't work when there are gaps and that is true and I should read the question better.
I should have used analytics to sort the results on fruitname
select id
, fruitname
, lead(id) over (order by fruitname) id_next
, lead(fruitname) over (order by fruitname) fruitname_next
from fruits;
If you are using MS SQL Server 2008 (not sure if available for previous versions)...
In the event that you are trying to find the next record and you do not have a unique ID to reference in an applicable manner, try using ROW_NUMBER(). See this link
Depending on how savvy your T-SQL skill is, you can create row numbers based on your sorting order. Then you can find more than just the previous and next record. Utilize it in views or sub-queries to find another record relative to the current record's row number.
SELECT cur.id as id, nxt.id as nextId, prev.id as prevId FROM video as cur
LEFT JOIN video as nxt ON nxt.id > cur.id
LEFT JOIN video as prev ON prev.id < cur.id
WHERE cur.id = 12
ORDER BY prev.id DESC, nxt.id ASC
LIMIT 1
If you want the item with previous and next item this query lets you do just that.
This also allows You to have gaps in the data!
How about this:
Select * from table where id = 1 + 1