need help a query in sql server 2008 - sql-server-2008

Hi I have doubt in sql server
Table : patient
patientno | refdoctor| loccode | status | sdate
100 | 31 |10 | 1 | 2012-05-03
100 | 32 |10 | 1 |1997-02-04
100 | 36 |10 | 1 |2014-09-16
100 |35 |10 | 1 |2013-05-03
100 | 50 |10 | 1 | 1988-05-08
100 | 20 |10 | 2 |2015-02-05
Table : targetpatient
patientno | refdoctor| loccode | status | sdate
100 | 21 | 10 | 2 | 2004-05-18
100 | 23 | 10 | 2 |2005-07-25
100 | 24 | 10 | 2 | 2006-06-22
100 | 26 | 10 | 2 |2012-05-14
100 | 28 |10 | 2 |2013-05-03
100 |29 |10 | 2 | 2014-09-26
100 | 33 | 10 | 2 | 2012-10-22
100 | 39 | 10 | 2 |2002-12-13
100 |41 | 10 | 2 |2012-05-13
Here I want output patient table relates status
statusvalue=5's sdate is less than or equal to checkvalue=2's sdate and
the difference between the dates should be less than 30days then given count
if that condition not fall then count must be return zero(0)
select o.patientno,o.loccode,o.status,o.sDate, count(*) as cnt
from patient o join targetpatient t on o.patientno=t.patientno and o.loccode=t.loccode and o.status in('1') and t.status in('2') and
o.sDate<=t.sdate
and datediff(dd,o.sdate,t.sdate)<=30
group by o.patientno,o.loccode,o.status,o.sDate
based on above query I got result like below:
patientno | loccode | status | sdate | count
100 | 10 | 1 |2012-05-03 | 2
100 | 10 | 1 |2013-05-03 | 1
100 | 10 | 1 |2014-09-16 | 1
but I want expected result like below
patientno | loccode | status | sdate | count
100 | 10 | 1 |2012-05-03 | 2
100 | 10 | 1 |2013-05-03 | 1
100 | 10 | 1 |2014-09-16 | 1
100 | 10 | 1 | 1997-02-04 | 0
100 | 10 |1 | 1988-05-08 | 0
please tell me how to write query to achive this task in sql server .

If you want to include the records that doesn't have any matches in the joined table you'll want to use a left join instead and do the count on a column in the joined table instead like this:
select o.patientno,o.loccode,o.status,o.sDate, count(t.sdate) as cnt
from patient o
left join targetpatient t on o.patientno = t.patientno
and o.loccode = t.loccode
and o.status in('1')
and t.status in('2')
and o.sDate <= t.sdate
and datediff(dd,o.sdate,t.sdate) <= 30
group by o.patientno,o.loccode,o.status,o.sDate
A left join will return all rows from the table on the left side (patient in your case) plus the matching rows from the right-hand side table. The rows that doesn't have any matches in the right-hand side table will get null as values.

Related

How to subtract a value from a sum of total in MySql LEFT JOIN Query

I have 2 tables.
SELECT * FROM purchases;
+------+---------+-----------+
|purid | total_q | dstatus |
+------+---------+-----------+
| 1 | 45 | DELIVERED |
| 2 | 50 | LOADING |
| 3 | 24 | DELIVERED |
| 4 | 15 | DELIVERED |
| 5 | 10 | DELIVERED |
+------+---------------------+
SELECT * FROM warehouse;
+------+-------+---------+
| wid | purid | total_q |
+------+-------+---------+
| 4 | 1 | 45 |
| 5 | 4 | 15 |
| 9 | 3 | 10 |
| 12 | 3 | 5 |
+------+-------+---------+
I want to get "delivered" purchases with its amounts which are not already included in warehouse table. Here is the demo where I stuck: DEMO
The query which I use is:
SELECT p.purid as purid, (p.total_q - IFNULL(w.total_q,0)) as ntq
FROM `purchases` as p
LEFT JOIN `warehouse` as w ON p.purid=w.purid
WHERE p.dstatus = "DELIVERED" AND (p.total_q - IFNULL(w.total_q,0)) > 0
My desired output:
+-------+------+
| purid | ntq |
+-------+------+
| 5 | 10 |
| 3 | 9 |
+------+-------+
The problem is I could not subtract "total_q (24) from purchases table" from "sum total_q(10+5) from warehouse table".
You can try to use subquery aggregate warehouse by purid before join otherwise you might get multiple rows.
Query #1
SELECT p.purid as purid,
p.total_q - IFNULL(w.total_q,0) as ntq
FROM `purchases` as p
LEFT JOIN (
SELECT purid,SUM(total_q) total_q
FROM warehouse
GROUP BY purid
) as w ON p.purid=w.purid
WHERE p.dstatus = "DELIVERED"
AND p.total_q - IFNULL(w.total_q,0) > 0;
purid
ntq
3
9
5
10
View on DB Fiddle

How to sum values of two tables and group by date

I am building a trading system where users need to know their running account balance by date for a specific user (uid) including how much they made from trading (results table) and how much they deposited or withdrew from their accounts (adjustments table).
Here is the sqlfiddle and tables: http://sqlfiddle.com/#!9/6bc9e4/1
Adjustments table:
+-------+-----+-----+--------+------------+
| adjid | aid | uid | amount | date |
+-------+-----+-----+--------+------------+
| 1 | 1 | 1 | 20 | 2019-08-18 |
| 2 | 1 | 1 | 50 | 2019-08-21 |
| 3 | 1 | 1 | 40 | 2019-08-21 |
| 4 | 1 | 1 | 10 | 2019-08-19 |
+-------+-----+-----+--------+------------+
Results table:
+-----+-----+-----+--------+-------+------------+
| tid | uid | aid | amount | taxes | date |
+-----+-----+-----+--------+-------+------------+
| 1 | 1 | 1 | 100 | 3 | 2019-08-19 |
| 2 | 1 | 1 | -50 | 1 | 2019-08-20 |
| 3 | 1 | 1 | 100 | 2 | 2019-08-21 |
| 4 | 1 | 1 | 100 | 2 | 2019-08-21 |
+-----+-----+-----+--------+-------+------------+
How do I get the below results for uid (1)
+--------------+------------+------------------+----------------+------------+
| ResultsTotal | TaxesTotal | AdjustmentsTotal | RunningBalance | Date |
+--------------+------------+------------------+----------------+------------+
| - | - | 20 | 20 | 2019-08-18 |
| 100 | 3 | 10 | 133 | 2019-08-19 |
| -50 | 1 | - | 84 | 2019-08-20 |
| 200 | 4 | 90 | 378 | 2019-08-21 |
+--------------+------------+------------------+----------------+------------+
Where RunningBalance is the current account balance for the particular user (uid).
Based on #Gabriel's answer, I came up with something like, but it gives me empty balance and duplicate records
SELECT SUM(ResultsTotal), SUM(TaxesTotal), SUM(AdjustmentsTotal), #runningtotal:= #runningtotal+SUM(ResultsTotal)+SUM(TaxesTotal)+SUM(AdjustmentsTotal) as Balance, date
FROM (
SELECT 0 AS ResultsTotal, 0 AS TaxesTotal, adjustments.amount AS AdjustmentsTotal, adjustments.date
FROM adjustments LEFT JOIN results ON (results.uid=adjustments.uid) WHERE adjustments.uid='1'
UNION ALL
SELECT results.amount AS ResultsTotal, taxes AS TaxesTotal, 0 as AdjustmentsTotal, results.date
FROM results LEFT JOIN adjustments ON (results.uid=adjustments.uid) WHERE results.uid='1'
) unionTable
GROUP BY DATE ORDER BY date
For what you are asking you would want to union then group the results from both tables, this should give the results you want. However, I recommend calculating the running balance outside of MySQL since this adds some complexity to our query.
Weird things could start to happen, for example, if someone already defined the #runningBalance variable as part of the queries scope.
SELECT aggregateTable.*, #runningBalance := ifNULL(#runningBalance, 0) + TOTAL
FROM (
SELECT SUM(ResultsTotal), SUM(TaxesTotal), SUM(AdjustmentsTotal)
, SUM(ResultsTotal) + SUM(TaxesTotal) + SUM(AdjustmentsTotal) as TOTAL
, date
FROM (
SELECT 0 AS ResultsTotal, 0 AS TaxesTotal, amount AS AdjustmentsTotal, date
FROM adjustments
UNION ALL
SELECT amount AS ResultsTotal, taxes AS TaxesTotal, 0 as AdjustmentsTotal, date
FROM results
) unionTable
GROUP BY date
) aggregateTable

Selecting rows that are not defined

How to select rows which are not defined? Like row 2 have undefined day 3 and row 3 have undefined day 1. I want them to be 0 in result set.
+----+-----+-------+
| id | day | count |
+----+-----+-------+
| 1 | 1 | 262 |
| 1 | 2 | 685 |
| 1 | 3 | 984 |
| 2 | 1 | 692 |
| 2 | 2 | 962 |
| 3 | 2 | 355 |
| 3 | 3 | 741 |
+----+-----+-------+
EDIT:
I want select count from days 1, 2 and 3 (not whole table) and display 0 on undefined day.
We can get all unique id values in a Derived Table.
For day, you seem to want only 1,2 and 3 only. So we can directly consider these values only using UNION ALL.
CROSS JOIN between them to get all possible combinations.
LEFT JOIN from all_combinations table to the main table on id and day.
We can use Coalesce() function to consider 0 value for count, for the cases where there is no matching row in the main table
Try the following:
SELECT all_combinations.id,
all_combinations.day,
COALESCE(t.count, 0) AS count
FROM
(
SELECT ids.id, days.day
FROM
(SELECT DISTINCT id FROM your_table) AS ids
CROSS JOIN
(SELECT 1 AS day UNION ALL SELECT 2 UNION ALL SELECT 3) AS days
) AS all_combinations
LEFT JOIN your_table AS t
ON t.id = all_combinations.id AND
t.day = all_combinations.day
Result:
| id | day | count |
| --- | --- | ----- |
| 1 | 1 | 262 |
| 2 | 1 | 692 |
| 3 | 1 | 0 |
| 1 | 2 | 685 |
| 2 | 2 | 962 |
| 3 | 2 | 355 |
| 1 | 3 | 984 |
| 2 | 3 | 0 |
| 3 | 3 | 741 |
View on DB Fiddle

MySql: Summing the latest amounts banked for each category and type

I have four MySql tables (simplified here):
Table 1: factions (just a list to reference)
id | name
1 | FactionName1
2 | FactionName2
Table 2: currencies (just a list to reference)
id | name
1 | Currency1
2 | Currency2
3 | Currency3
Table 3: events (just a list to reference)
id | name | date
1 | Evebt1 | 2013-10-16
2 | Event2 | 2013-10-18 (Note: date out of order)
3 | Event3 | 2013-10-17
Table 4: event_banking (data entered after each event, remaining amount of each currency for each group)
id | faction_id | currency_id | event_id | amount
1 | 1 | 1 | 1 | 10
2 | 1 | 1 | 2 | 20
3 | 1 | 1 | 3 | 30
4 | 1 | 2 | 1 | 40
5 | 1 | 2 | 2 | 50
6 | 1 | 2 | 3 | 60
7 | 1 | 3 | 1 | 70
8 | 1 | 3 | 2 | 80
9 | 1 | 3 | 3 | 90
10 | 2 | 1 | 1 | 100
11 | 2 | 1 | 2 | 110
12 | 2 | 1 | 3 | 120
13 | 2 | 2 | 1 | 130
14 | 2 | 2 | 2 | 140
15 | 2 | 2 | 3 | 150
16 | 2 | 3 | 1 | 160
17 | 2 | 3 | 3 | 170
Note: Faction 2 didn't bank Currency 3 for Event 2
What I'm looking to be able to do is to get, for each currency, the total of the last banked (date wise) for each faction. (ie How much of each currency is currently banked in total if all factions are merged)
So, I need a table looking something like:
currency_id | total
1 | 130 (eg 20 + 110)
2 | 190 (eg 50 + 140)
3 | 250 (eg 80 + 170) <- Uses Event 3 for Group 2 as Event 2 doesn't exist
I can do basic joins etc, but I'm struggling to be able to filter the results so that I get the latest results for each Faction x Currency x Event so I can then sum them together to get the final total amounts for each currency.
I've tried various permutations of LEFT OUTER JOINs, GROUP BYss & HAVING COUNTs, and had some interesting (but incorrect results), and a variety of different error codes, but nothing remotely close to what I need.
Can anyone help?
I guess you can go on with something like this:
select eb.currency_id, sum(amount) as total
from events e
inner join (
select faction_id, currency_id, max(date) as md
from event_banking eb
inner join events e
on eb.event_id = e.id
group by faction_id, currency_id
) a
on e.date = a.md
inner join event_banking eb
on e.id = eb.event_id
and a.faction_id = eb.faction_id
and a.currency_id = eb.currency_id
group by currency_id;
Here is SQL Fiddle

MySQL get total number of orders and sum of total by user

I have a table called orders where I store information about orders made by an User.
order_id | user_id | amount
+++++++++++++++++++++++++++++++++++
1 | 1 | 100
2 | 1 | 200
3 | 2 | 200
4 | 3 | 100
5 | 3 | 100
6 | 4 | 500
What I want as final outcome is,
Number of Orders made by an user and total value of those orders.
So in above case output should look like,
user_id | count | sum
+++++++++++++++++++++++++++++++++++
1 | 2 | 300
2 | 1 | 200
3 | 3 | 600
4 | 1 | 500
What you need here is, just a GROUP BY with COUNT and SUM like so:
SELECT
user_id,
COUNT(User_id) Count,
SUM(amount) Sum
FROM Orders
GROUP BY user_id;
SQL Fiddle Demo
This will give you:
| USER_ID | COUNT | SUM |
-------------------------
| 1 | 2 | 300 |
| 2 | 1 | 200 |
| 3 | 2 | 200 |
| 4 | 1 | 500 |